zoukankan      html  css  js  c++  java
  • 12,享元模式(Flyweight Pattern)是以共享的方式高效的支持大量的细粒度的对象。

    想想我们编辑文档用的wps,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,最好的办法就是共享其中相同的部分,使得需要创建的对象降到最小,这个就是享元模式的核心,即运用共享技术有效地支持大量细粒度的对象。

    享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。

    内蕴状态:是存储在享元对象内部并且不会随环境改变而改变。因此内蕴状态并可以共享。

    外蕴状态:是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态与内蕴状态是相互独立的。

    抽象享元类(Flyweight)

    它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态(Exte的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。

    具体享元类(ConcreteFlyweight)

    具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。

    不能共享的具体享元类(UnsharableFlyweight)

    不能共享的享元类,又叫做复合享元类。一个复合享元对象是由多个单享元对象组成,这些组成的对象是可以共享的,但是复合享元类本身并不能共享。

    享元工厂类(FlyweightFactoiy)

    享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。

    客户类(Client)

    客户类需要自行存储所有享元对象的外蕴状态。

      1 // CplusplusFlyweight.cpp : Defines the entry point for the console application.  
      2 //  
      3   
      4 #include "stdafx.h"  
      5 #include <iostream>  
      6 #include <map>  
      7 using namespace std;  
      8 class Character    
      9 {  
     10 public:  
     11     virtual ~Character(){};  
     12   
     13     virtual void SetSize(int, int) = 0;  
     14     virtual void Display() = 0;  
     15 protected:  
     16     Character(){};  
     17     char m_chSymbol;  
     18     int m_nWeight;  
     19     int m_nHeight;  
     20 };  
     21   
     22 class CharacterA : public Character  
     23 {  
     24 public:  
     25     CharacterA();  
     26     virtual ~CharacterA();  
     27   
     28     void SetSize(int, int);  
     29     void Display();  
     30 };  
     31   
     32 CharacterA::CharacterA()  
     33 {  
     34     this->m_chSymbol = 'A';  
     35     this->m_nWeight = 100;  
     36     this->m_nHeight = 200;  
     37 }  
     38   
     39 CharacterA::~CharacterA()  
     40 {  
     41   
     42 }  
     43 void CharacterA::SetSize(int nWeight, int nHeight)  
     44 {  
     45     this->m_nWeight = nWeight;  
     46     this->m_nHeight = nHeight;  
     47 }  
     48 void CharacterA::Display()  
     49 {  
     50     cout << "CharacterA:" << m_chSymbol << "(" << m_nWeight << "," << m_nHeight << ")" << endl;  
     51 }  
     52   
     53 class CharacterB : public Character  
     54 {  
     55 public:  
     56     CharacterB();  
     57     virtual ~CharacterB();  
     58   
     59     void SetSize(int, int);  
     60     void Display();  
     61 };  
     62   
     63 CharacterB::CharacterB()  
     64 {  
     65     this->m_chSymbol = 'B';  
     66     this->m_nWeight = 100;  
     67     this->m_nHeight = 200;  
     68 }  
     69   
     70 CharacterB::~CharacterB()  
     71 {  
     72   
     73 }  
     74   
     75 void CharacterB::SetSize(int nWeight, int nHeight)  
     76 {  
     77     this->m_nWeight = nWeight;  
     78     this->m_nHeight = nHeight;  
     79 }  
     80   
     81 void CharacterB::Display()  
     82 {  
     83     cout << "CharacterB:" << m_chSymbol << "(" << m_nWeight << "," << m_nHeight << ")" << endl;  
     84 }  
     85   
     86 class CharacterFactory    
     87 {  
     88 public:  
     89     CharacterFactory();  
     90     virtual ~CharacterFactory();  
     91   
     92     Character* GetCharacter(char);  
     93 private:  
     94     std::map<char, Character*> m_mChar;  
     95 };  
     96   
     97 CharacterFactory::CharacterFactory()  
     98 {  
     99     m_mChar.insert(make_pair<char, Character*>('A', new CharacterA));  
    100     m_mChar.insert(make_pair<char, Character*>('B', new CharacterB));  
    101 }  
    102   
    103 CharacterFactory::~CharacterFactory()  
    104 {  
    105   
    106 }  
    107   
    108 Character* CharacterFactory::GetCharacter(char chIn)  
    109 {  
    110     map<char, Character*>::iterator it = m_mChar.find(chIn);  
    111     if(it != m_mChar.end())  
    112     {  
    113         return (Character*)it->second;  
    114     }  
    115   
    116     return NULL;  
    117 }  
    118   
    119 int _tmain(int argc, _TCHAR* argv[])  
    120 {  
    121     CharacterFactory* pFactory = new CharacterFactory;  
    122   
    123     //内蕴状态 存储在享元对象内部并且不会随环境改变而改变  
    124     Character* ch1 = pFactory->GetCharacter('A');  
    125     ch1->Display();  
    126   
    127     //外蕴状态 客户端保存  
    128     Character* ch2 = pFactory->GetCharacter('B');  
    129     ch2->SetSize(500, 800);  
    130     ch2->Display();  
    131     return 0;  
    132 }  

    实例二:

      1 #include <iostream>
      2 using namespace std;
      3 #include "string"
      4 #include "map"
      5 
      6 class Person
      7 {
      8 public:
      9     Person(string name, int age)
     10     {
     11         this->m_name = name;
     12         this->age = age;
     13     }
     14     virtual void printT() = 0;
     15 
     16 protected:
     17     string    m_name;
     18     int        age;
     19 };
     20 
     21 class Teacher : public Person
     22 {
     23 public:
     24     Teacher(string name, int age, string id) : Person(name, age)
     25     {
     26         this->m_id = id;
     27     }
     28     void printT()
     29     {
     30         cout << "name:" << m_name << " age:" << age << " m_id:" << m_id << endl;
     31      }
     32 protected:
     33 private:
     34     string    m_id;
     35 };
     36 
     37 
     38 //完成 老师结点 存储
     39 
     40 class FlyWeightTeacherFactory 
     41 {
     42 public:
     43     FlyWeightTeacherFactory()
     44     {
     45         map1.clear();
     46     }
     47 
     48     ~FlyWeightTeacherFactory()
     49     {
     50         while ( !map1.empty())
     51         {
     52             Person *tmp = NULL;
     53             map<string, Person *>::iterator it = map1.begin();
     54             tmp = it->second;
     55             map1.erase(it); //把第一个结点 从容器中删除
     56             delete tmp;
     57         }
     58     }
     59 
     60     Person * GetTeacher(string id)
     61     {
     62         Person *tmp = NULL;
     63         map<string, Person *>::iterator it ;
     64         it = map1.find(id);
     65         if (it == map1.end()) //没有找到
     66         {
     67             string    tmpname;
     68             int        tmpage;
     69             cout << "
    请输入老师name:";
     70             cin >> tmpname;
     71 
     72             cout << "
    请输入老师age:";
     73             cin >> tmpage;
     74 
     75             tmp = new Teacher(tmpname, tmpage, id);
     76             map1.insert(pair<string, Person*>(id, tmp) );
     77         }
     78         else
     79         {
     80             tmp = it->second;
     81         }
     82         return tmp;
     83     }
     84 private:
     85     map<string, Person *> map1;
     86 
     87 };
     88 
     89 void main()
     90 {
     91     Person *p1 = NULL;
     92     Person *p2 = NULL;
     93     FlyWeightTeacherFactory *fwtf = new FlyWeightTeacherFactory;
     94     p1 = fwtf->GetTeacher("001");
     95     p1->printT();
     96 
     97     p2 = fwtf->GetTeacher("001");
     98     p2->printT();
     99 
    100     delete fwtf;
    101     
    102     cout<<"hello..."<<endl;
    103     system("pause");
    104     return ;
    105 }

    要点

    1、面向对象很好的解决了抽象性的问题,但是作为一个运行在机器中的程序实体,我们需要考虑对象的代价问题。Flyweight设计模式主要解决面向对象的代价问题,一般不触及面向对象的抽象性问题。

    2、Flyweight采用对象共享的做法来降低系统中对象的个数,从而降低细粒度对象给系统带来的内存压力。在具体实现方面,要注意对象状态的处理。

    3、享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。另外它将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

    适用性

    当以下所有的条件都满足时,可以考虑使用享元模式:

    1、一个系统有大量的对象。 

    2、这些对象耗费大量的内存。 

    3、这些对象的状态中的大部分都可以外部化。 

    4、这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。 

    5、软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。

    满足以上的这些条件的系统可以使用享元对象。最后,使用享元模式需要维护一个记录了系统已有的所有享元的表,而这需要耗费资源。因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。

    优缺点

    享元模式的优点在于它大幅度地降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:

    1、享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。

    2、享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。

  • 相关阅读:
    javaMap
    javaCollections
    java线程
    mysql插入,删除
    mysql基础(1)
    javaSet,Date
    中青杯数学建模大赛
    javaJDBC
    中秋记事~~项目开发
    太高兴了,今天有人送我吃月饼!
  • 原文地址:https://www.cnblogs.com/D-DZDD/p/7342039.html
Copyright © 2011-2022 走看看