C++设计模式之享元模式(Flyweight)

享元模式顾名思义就是羽量级模式或者蝇级模式,形容体量小的应用,该模式主要的设计目的是为了迎合系统大量相似数据的应用而生,减少用于创建和操作相似的细碎对象所花费的成本。大量的对象会消耗高内存,享元模式给出了一个解决方案,即通过共享对象来减少内存负载。

作用

通过复用相同的对象来减少对象的创建数量,创建更小的对象组,并通过共享实现重用。通过归类,将对象的属性分为内蕴状态和外蕴状态。要创建具体的享元对象,我们需要创建一个享元工厂来统一管理对象的生成和输出,享元工厂是实现享元模式的关键。

举个例子,享元模式可以看成是一个工具箱,而享元对象就是工具箱内的具体的工具,我们在使用工具的时候,不必每回临时的制造工具,而是直接从工具箱里找到工具进行使用,这样就大大节约了制造工具的成本时间和工具占用的空间。

享元模式比较迷惑在于理解两种状态的分类,内蕴状态是对象本身的属性,在生成对象以后一般不会进行改变,比如工具中的属性:名字、大小、重量等,还有就是我们一般需要一个关键性的属性作为其区别于其他对象的key,如工具的话我们可以把名称作为找到工具的唯一标识。

外蕴状态是对象的外部描述,是每个对象的可变部分,比如对工具的使用地点、使用时间、使用人、工作内容的描述,这些属性不属于对象本身,而是根据每回使用情况进行变化的,这就需要制作成接口进行外部调用,而外蕴状态的维护是由调用者维护的,对象内不进行维护。

类视图

实现

//Flyweight
class tool
{
public:
  //内蕴状态
  string name;
  int nSize;
  int nWeight;
public:
  //外蕴状态
  virtual int used(string person, string work)=0;
}
//ConcreteFlyweight
class hammer : public tool
{
public:
  hammer():name("hammer"){}
  int used(string person, string work)
  {
    cout<< person <<"use"<<name<<"to" << work;
  }

}
//ConcreteFlyweight
class screwdriver : public tool
{
  screwdriver():name("screwdriver"){}
  int used(string person, string work)
  {
    cout<< person <<"use"<< name << " to" << work;
  }
}
//ConcreteFlyweight
class saw : public tool
{
  saw():name("saw"){}
  int used(string person, string work)
  {
    cout<< person <<"use"<< name <<"to" << work;
  }
}

//FlyweightFactory
class toolbox
{
public:
  toolbox();
  virtual ~toolbox()
  {
    map<string,tool*>::iterator it = m_tool.find(toolname);
    for(it=m_tool.begin();it!=m_tool.end();it++)
    {
      delete it.second;
    }

  }
  tool* GetTool(string toolname)
  {
    map<string,tool*>::iterator it = m_tool.find(toolname);
    if(it != m_tool.end())
    {
      return (tool*) it.second;
    }
    else
    {
      tool* tooltemp= NULL;
      if(toolname == "hammer")
        tooltemp = new hammer();
      else if(toolname == "screwdriver")
        tooltemp = new screwdriver();
      else if(toolname == "saw")
        tooltemp = new saw();

      if(tooltemp !=NULL)
        m_tool.insert(make_pair<string,tool*>(toolname,tooltemp));
      return tooltemp;
    }
  }
private:
  map<string,tool*> m_tool;
}

int main()
{
  //外蕴状态 由调用者维护
  string person1 = "zhangsan";
  string person2 = "lisi";
  string work1 = "make desk";
  string work2 = "repair bike";
  //生成工厂
  toolbox tBox;
  //获取享元
  tool* tool1 = tBox.GetTool("hammer");
  tool1.used(person1,work1);

  tool* tool2 = tBox.GetTool("screwdriver");
  tool2.used(person2,work2);
}

单享元(share)和复合享元(unshare)
复合享元也既是unshareFlyweight,其不再是单一的对象,而是一系列对象的组合,他们的关系由原来的一对一的关系,变成了一对多的关系。
举例说明,如【DP】中比较经典的围棋的例子,单享元模式下,我们对围棋的颜色种类进行共享,再棋盘的工厂类中只需包含黑白两颗棋子,就能完成对棋盘下棋的整个操作,而不用对每一个棋子进行操作。但是有一天需求增加了对胜负的要求,那么就需要对棋子的坐标进行记录,对于黑白两种颜色的棋子,相对应的就会有相同颜色棋子的坐标数组容器,like:map<string,vector<Point>> 这样的结构。

应用场景

  • 需要创建大量对象时;
  • 大多数对象可以分为内蕴和外蕴状态;
  • 应用程序需要使用多种对象,并且重复使用;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • C++设计模式编程中使用Bridge桥接模式的完全攻略
  • C++设计模式之桥接模式
  • C++设计模式之组合模式(Composite)
  • C++设计模式之策略模式(Strategy)
  • C++设计模式之模板方法模式(TemplateMethod)
  • C++设计模式之观察者模式(Observer)
  • C++设计模式之迭代器模式(Iterator)
  • C++设计模式之适配器模式(Adapter)
  • C++设计模式之建造者模式(Builder)
  • C++设计模式之桥接模式(Bridge)
(0)

相关推荐

  • C++设计模式编程中使用Bridge桥接模式的完全攻略

    桥接模式将抽象(Abstraction)与实现(Implementation)分离,使得二者可以独立地变化. 桥接模式典型的结构图为: 在桥接模式的结构图中可以看到,系统被分为两个相对独立的部分,左边是抽象部分,右边是实现部分,这两个部分可以互相独立地进行修改:例如上面问题中的客户需求变化,当用户需求需要从 Abstraction 派生一个具体子类时候,并不需要像上面通过继承方式实现时候需要添加子类 A1 和 A2 了.另外当上面问题中由于算法添加也只用改变右边实现(添加一个具体化子类),而右边

  • C++设计模式之桥接模式

    问题描述 现在要去画一个图形,图形有长方形.圆形和扇形等等:而图形又可以加上不同的颜色,然后,我们就可以画出红色的长方形,绿色的长方形:红色的圆形,绿色的圆形等等.而这种图形的形状在变化,图形的颜色也在变化,当使用代码去实现时,如何面对这种多方面的变化呢?这就要说到今天的桥接模式了. 什么是桥接模式? 对于上述的图形与颜色的问题时,很多时候,我们让各个图形类继承颜色类,比如: 复制代码 代码如下: class CShape { }; class CRectangle : public CShap

  • C++设计模式之模板方法模式(TemplateMethod)

    模板方法模式使用继承来实现模式的功能,在基类使用一个方法来定义算法的各个步骤,这些步骤(方法)的具体实现会放到子类中,通过这样来实现不同算法对象的算法拼合,完成该对象整体算法的实现. 作用 模板方法中定义了具体操作中所使用算法的各个步骤,并将其实现交由子类完成,从而实现多种不同的功能: 类视图 实现 class Lunch { public: Lunch(){} virtual ~Lunch(){} void feed() { cooking(); eating(); cleaning(); }

  • C++设计模式之适配器模式(Adapter)

    适配器模式顾名思义在于接口的转换,最形象的例子就如两口转三口电源适配器,口子的数量可以理解为参数数量,一如我们调用三个参数的接口,而提供的接口只有两个参数,那么久需要适配器类进行接口的扩展改造,这就是适配器模式存在的最主要意义. 作用 将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,使控制范围之外的一个原有对象与某个接口匹配.适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况. 想使用一个已经存在的类,但如果它的接

  • C++设计模式之观察者模式(Observer)

    观察者模式通常的叫法叫做订阅-发布模式,类似于报刊杂志的订阅,观察者和被观察者就是读者和邮局的关系,读者先要在邮局订阅想要的报刊,当报刊发行时,邮局会将报刊邮寄到读者家里.观察者(Observer)和被观察者(Listener)也是这种关系,Observer将自己attach到Listener中,当Listener触发时Notify所有Observer. 作用 在观察者模式中,被观察者维护观察者对象的集合,当被观察者对象变化时,它会通知观察者.观察者模式主要是用于解决对象之间一对多的关系. 类视

  • C++设计模式之迭代器模式(Iterator)

    迭代器在STL运用广泛,类似容器的迭代已经成为其重要特性,而迭代器模式则是利用迭代器概念进行的抽象运用,迭代器模式运用广泛和有用,因为其能够不考虑数据的存储方式,而是直接面对数据进行迭代,也就是说我们不用考虑集合是数组(或vector).链表.栈还是队列,而是通过统一的接口进行顺序的访问. 作用 迭代器模式提供了一种顺序访问容器中元素的方法,而无需了解器内部的类型和结构,该模式的核心思想将访问和遍历容器对象的功能交给一个外部的迭代器对象,该迭代器定义了访问聚合对象的接口, 类视图 实现 clas

  • C++设计模式之策略模式(Strategy)

    策略模式将不同算法的逻辑抽象接口封装到一个类中,通过组合和多态结合的方式来进行不同算法具体的实现. 作用 策略模式是一种定义一系列算法的方法,Strategy类层次为Context定义了一系列的可重用的算法或行为, 所有的算法以相同的方式进行调用,减少了算法类之间的耦合 类视图 实现 class Strategy { public: ~Strategy(); virtual void AlgrithmInterface()=0; protected: Strategy(); }; class C

  • C++设计模式之建造者模式(Builder)

    建造者模式与工厂模式最大的区别在与建造者模式更注重的是创建的一系列过程,如流水化作业,工厂模式强调的是区分不同的工厂和产品,而建造者模式更注重的统一不同产品在流水线上的工序,达到统一作业. 作用 建造者模式是将一个复杂对象和他的构造和组装过程分离,这样再重复创建不同对象时使用相同的流程进行建造.对于调用者来说,只需要知道产品的类型,而不需要知道具体的组装过程. 类视图 代码实现 class Builder { public: virtual void SelectCpu()= 0; virtua

  • C++设计模式之桥接模式(Bridge)

    桥接模式属于先天模式,这里的先天模式就是说一开始就要把结构搭建好,方便后来的扩展,而不是对已经出现的模块和接口进行改进扩展的.桥接的核心在于实体类和操作类之间的聚合关系,这个聚合关系就是我们所说的"桥",不同于装饰.代理和适配器模式的中的聚合关系,桥接不存在两者之间的继承关系,操作类是完全解耦的,而实体类对于操作类也只是弱耦合. 作用 将抽象部份与它的实现部份分离,使它们都可以独立地变化. 类视图 实现 //操作类 class action { public: virtual void

  • C++设计模式之组合模式(Composite)

    组合模式为了描述分支包含关系,也就是我们说的树形关系,其对象分为枝和叶,每一枝可包含枝和叶,直到全部为叶节点.我们对枝和叶进行行为抽象,可认为枝和叶都是Component,而叶是最小的操作单元,其下不存在枝和叶,而枝作为Composite里面存有其下枝和叶的组件列表. 作用 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性 类视图 实现 #include <iostream> #include <list> #in

随机推荐