C++设计模式---享元模式----浪费可耻,节俭光荣

概述

一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。

想想我们编辑文档用的word,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,那么我们如何去避免系统中出现大量相同或相似的对象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?

享元模式正为解决这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个享元对象,将其放在享元池中,需要时再从享元池取出。

实现策略

作用:运用共享技术有效地支持大量细粒度的对象。

内部状态intrinsic和外部状态extrinsic:

1)Flyweight模式中,最重要的是将对象分解成intrinsic和extrinsic两部分。
2)内部状态:在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态
3)外部状态:而随环境改变而改变的,取决于应用环境,或是实时数据,这些不可以共享的东西就是外部状态了。
4)内部状态和外部状态之间的区别:
在Flyweight模式应用中,通常修改的是外部状态属性,而内部状态属性一般都是用于参考或计算时引用。
Flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部状态则由Client对象存储或计算。当用户调用Flyweight对象的操作时,将该状态传递给它。

以文字处理软件为例:
内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。如字符代码,字符大小……
外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight,如字符位置,字符颜色……

组成

①Flyweight:

享元类的基类,定义一个接口,通过这个接口Flyweight可以接受并作用于外部状态。

②ConcreteFlyweight:

实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic);即,它必须独立于ConcreteFlyweight对象的场景。

③UnsharedConcreteFlyweight:

并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,④UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。

⑤FlyweightFactory:

1) 创建并管理Flyweight对象。
2)确保合理地共享Flyweight。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)

⑥Client

1)维持一个对Flyweight的引用。
2)计算或存储一个(多个)Flyweight的外部状态。

UML

示例代码

// Flyweight.h

[cpp] view plain copy print?

  1. // Flyweight.h  
  2. #ifndef _FLYWEIGHT_H_  
  3. #define _FLYWEIGHT_H_  
  4.   
  5. #include <string>  
  6. #include <vector>  
  7.   
  8. using namespace std;  
  9.   
  10. //基类,定义操作接口Operation  
  11. class Flyweight  
  12. {  
  13. public:  
  14.     //操作外部状态extrinsicState  
  15.     virtual void Operation(const string& extrinsicState) = 0;  
  16.     string GetIntrinsicState( );  
  17.     virtual ~Flyweight( );  
  18. protected:  
  19.     Flyweight(string intrinsicState);  
  20. private:  
  21.       
  22.     // 内部状态,也可以放在ConcreteFlyweight中  
  23.     string _intrinsicState;  
  24. };  
  25.   
  26.   
  27. /* 
  28. ConcreteFlyweight:实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。 
  29. ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic); 
  30. 即,它必须独立于ConcreteFlyweight对象的场景。 
  31. */  
  32. class ConcreteFlyweight : public Flyweight  
  33. {  
  34. public:  
  35.     //实现接口函数  
  36.     virtual void Operation(const string& extrinsicState);  
  37.     ConcreteFlyweight(string intrinsicState);  
  38.     ~ConcreteFlyweight();  
  39. };  
  40.   
  41.   
  42. /* 
  43. UnsharedConcreteFlyweight:并非所有的Flyweight子类都需要被共享。 
  44. Flyweight接口使共享成为可能,但它并不强制共享。 
  45. 在Flyweight对象结构的某些层次, 
  46. UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。 
  47. */  
  48. class UnsharedConcreteFlyweight:public Flyweight  
  49. {  
  50. public:  
  51.     virtual void Operation(const string& extrinsicState);  
  52.     UnsharedConcreteFlyweight(string intrinsicState);  
  53.     ~UnsharedConcreteFlyweight();  
  54. };  
  55.   
  56. class FlyweightFactory  
  57. {  
  58. public:  
  59.     FlyweightFactory();  
  60.     ~FlyweightFactory();  
  61.     //获得一个请求的Flyweight对象  
  62.     Flyweight* GetFlyweight(string key);  
  63.     //获取容器中存储的对象数量  
  64.     void GetFlyweightCount();  
  65. protected:  
  66. private:  
  67.     //保存内部状态对象的容器  
  68.     vector<Flyweight*> m_vecFly;  
  69. };  
  70. #endif  
// Flyweight.h
#ifndef _FLYWEIGHT_H_
#define _FLYWEIGHT_H_

#include <string>
#include <vector>

using namespace std;

//基类,定义操作接口Operation
class Flyweight
{
public:
    //操作外部状态extrinsicState
    virtual void Operation(const string& extrinsicState) = 0;
    string GetIntrinsicState( );
    virtual ~Flyweight( );
protected:
    Flyweight(string intrinsicState);
private:

	// 内部状态,也可以放在ConcreteFlyweight中
    string _intrinsicState;
};

/*
ConcreteFlyweight:实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。
ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的(intrinsic);
即,它必须独立于ConcreteFlyweight对象的场景。
*/
class ConcreteFlyweight : public Flyweight
{
public:
    //实现接口函数
    virtual void Operation(const string& extrinsicState);
    ConcreteFlyweight(string intrinsicState);
    ~ConcreteFlyweight();
};

/*
UnsharedConcreteFlyweight:并非所有的Flyweight子类都需要被共享。
Flyweight接口使共享成为可能,但它并不强制共享。
在Flyweight对象结构的某些层次,
UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
*/
class UnsharedConcreteFlyweight:public Flyweight
{
public:
    virtual void Operation(const string& extrinsicState);
    UnsharedConcreteFlyweight(string intrinsicState);
    ~UnsharedConcreteFlyweight();
};

class FlyweightFactory
{
public:
    FlyweightFactory();
    ~FlyweightFactory();
    //获得一个请求的Flyweight对象
    Flyweight* GetFlyweight(string key);
    //获取容器中存储的对象数量
    void GetFlyweightCount();
protected:
private:
    //保存内部状态对象的容器
    vector<Flyweight*> m_vecFly;
};
#endif

// Flyweight.cpp

[cpp] view plain copy print?

  1. // Flyweight.cpp  
  2. #include "Flyweight.h"  
  3. #include <iostream>  
  4.   
  5. using namespace std;  
  6.   
  7. Flyweight::Flyweight(string intrinsicState)  
  8. {  
  9.     this->_intrinsicState = intrinsicState;  
  10. }  
  11.   
  12. Flyweight::~Flyweight()  
  13. {}  
  14.   
  15. string Flyweight::GetIntrinsicState()  
  16. {  
  17.     return this->_intrinsicState;  
  18. }  
  19.   
  20. ConcreteFlyweight::ConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)  
  21. {  
  22. }  
  23.   
  24. ConcreteFlyweight::~ConcreteFlyweight()  
  25. {  
  26. }  
  27.   
  28. void ConcreteFlyweight::Operation(const string& extrinsicState)  
  29. {  
  30.     cout << this->GetIntrinsicState() << endl;  
  31.     cout << extrinsicState << endl;  
  32. }  
  33.   
  34. UnsharedConcreteFlyweight::UnsharedConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)  
  35. {  
  36. }  
  37.   
  38. UnsharedConcreteFlyweight::~UnsharedConcreteFlyweight()  
  39. {  
  40. }  
  41.   
  42. void UnsharedConcreteFlyweight::Operation(const string& extrinsicState)  
  43. {  
  44.     cout << "extrinsicState" << endl;  
  45. }  
  46.   
  47. FlyweightFactory::FlyweightFactory()  
  48. {}  
  49.   
  50. FlyweightFactory::~FlyweightFactory()  
  51. {}  
  52.   
  53. //若该对象已存在,直接返回,否则新建一个对象,存入容器中,再返回  
  54. Flyweight* FlyweightFactory::GetFlyweight(string key)  
  55. {  
  56.     vector<Flyweight*>::iterator iter = this->m_vecFly.begin();  
  57.     for(;iter!= this->m_vecFly.end();iter++)  
  58.     {  
  59.         if((*iter)->GetIntrinsicState() == key)  
  60.         {  
  61.             return *iter;  
  62.         }  
  63.     }  
  64.     Flyweight* fly = new ConcreteFlyweight(key);  
  65.     this->m_vecFly.push_back(fly);  
  66.     return fly;  
  67. }  
  68.   
  69. void FlyweightFactory::GetFlyweightCount()  
  70. {  
  71.     cout << this->m_vecFly.size() << endl;  
  72. }  
// Flyweight.cpp
#include "Flyweight.h"
#include <iostream>

using namespace std;

Flyweight::Flyweight(string intrinsicState)
{
    this->_intrinsicState = intrinsicState;
}

Flyweight::~Flyweight()
{}

string Flyweight::GetIntrinsicState()
{
    return this->_intrinsicState;
}

ConcreteFlyweight::ConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
{
}

ConcreteFlyweight::~ConcreteFlyweight()
{
}

void ConcreteFlyweight::Operation(const string& extrinsicState)
{
    cout << this->GetIntrinsicState() << endl;
    cout << extrinsicState << endl;
}

UnsharedConcreteFlyweight::UnsharedConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
{
}

UnsharedConcreteFlyweight::~UnsharedConcreteFlyweight()
{
}

void UnsharedConcreteFlyweight::Operation(const string& extrinsicState)
{
    cout << "extrinsicState" << endl;
}

FlyweightFactory::FlyweightFactory()
{}

FlyweightFactory::~FlyweightFactory()
{}

//若该对象已存在,直接返回,否则新建一个对象,存入容器中,再返回
Flyweight* FlyweightFactory::GetFlyweight(string key)
{
    vector<Flyweight*>::iterator iter = this->m_vecFly.begin();
    for(;iter!= this->m_vecFly.end();iter++)
    {
        if((*iter)->GetIntrinsicState() == key)
        {
            return *iter;
        }
    }
    Flyweight* fly = new ConcreteFlyweight(key);
    this->m_vecFly.push_back(fly);
    return fly;
}

void FlyweightFactory::GetFlyweightCount()
{
    cout << this->m_vecFly.size() << endl;
}

main.cpp

[cpp] view plain copy print?

  1. #include "Flyweight.h"  
  2. #include <iostream>  
  3. #include <string>  
  4.   
  5. using namespace std;  
  6.   
  7. int main()  
  8. {  
  9.     //外部状态extrinsicState  
  10.     string extrinsicState = "ext";  
  11.   
  12.     //工厂对象,工厂对象  
  13.     FlyweightFactory* fc = new FlyweightFactory();  
  14.   
  15.     //向工厂申请一个Flyweight对象,且该对象的内部状态值为“hello”  
  16.     Flyweight* fly = fc->GetFlyweight("hello");  
  17.   
  18.     Flyweight* fly1 = fc->GetFlyweight("hello");  
  19.   
  20.     //应用外部状态  
  21.     fly->Operation(extrinsicState);  
  22.   
  23.     fc->GetFlyweightCount();  
  24.   
  25.     return 0;  
  26. }  
#include "Flyweight.h"
#include <iostream>
#include <string>

using namespace std;

int main()
{
    //外部状态extrinsicState
    string extrinsicState = "ext";

    //工厂对象,工厂对象
    FlyweightFactory* fc = new FlyweightFactory();

    //向工厂申请一个Flyweight对象,且该对象的内部状态值为“hello”
    Flyweight* fly = fc->GetFlyweight("hello");

    Flyweight* fly1 = fc->GetFlyweight("hello");

    //应用外部状态
    fly->Operation(extrinsicState);

    fc->GetFlyweightCount();

    return 0;
}

Makefile

[cpp] view plain copy print?

  1. CC = gcc  
  2. CXX = g++  
  3.   
  4. OBJECT = Flyweight.o main.o  
  5. TARGET = Flyweight.exe  
  6. INC = -I./  
  7.   
  8.   
  9. $(TARGET) : $(OBJECT)  
  10.     $(CXX) $(OBJECT) -o $(TARGET)  
  11.   
  12. %.o : %.cpp  
  13.     $(CXX) -c $< -o $@ $(INC)  
  14.   
  15.   
  16. .PHONY : clean  
  17. clean :  
  18.     del $(OBJECT) $(TARGET)  
  19.     rm -rf $(OBJECT) $(TARGET)  
CC = gcc
CXX = g++

OBJECT = Flyweight.o main.o
TARGET = Flyweight.exe
INC = -I./

$(TARGET) : $(OBJECT)
	$(CXX) $(OBJECT) -o $(TARGET)

%.o : %.cpp
	$(CXX) -c $< -o $@ $(INC)

.PHONY : clean
clean :
	del $(OBJECT) $(TARGET)
	rm -rf $(OBJECT) $(TARGET)

参考:

另外一个围棋的例子:

http://blog.csdn.net/wuzhekai1985/article/details/6670298

转载:http://blog.csdn.net/gatieme/article/details/24925741

时间: 2016-05-18

C++设计模式---享元模式----浪费可耻,节俭光荣的相关文章

跟屌丝大哥学习设计模式--享元模式

四.举例 这里就以去餐馆吃饭为例详细的说明下享元模式的使用方式.去菜馆点菜吃饭的过程大家一定都是轻车熟路了,这里就不赘述.在例子中我使用了一个list来存放外蕴状态和内蕴状态的对应关系,而且提供了查询每个客人点菜情况的方法.内蕴状态在这里代表了菜肴的种类,而外蕴状态就是每盘菜肴的点菜人.  A 让我们先来看看单纯享元模式的实现吧.     先看下抽象享元角色的定义:GoF对享元模式的描述是:运用共享技术有效地支持大量细粒度的对象. Flyweight模式是构造型模式之一,它通过与其他类似对象共享

PHP设计模式——享元模式

声明:本系列博客参考资料<大话设计模式>,作者程杰.         享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分状态是可以分享.常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元.               UML类图:                    角色分析:           享元工厂角色(FWFactory):创建并管理BlogModel对象.

.NET设计模式-享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern) --.NET设计模式系列之十三 Terrylee,2006年3月 摘要:面向对象的思想很好地解决了抽象性的问题,一般也不会出现性能上的问题.但是在某些情况下,对象的数量可能会太多,从而导致了运行时的代价.那么我们如何去避免大量细粒度的对象,同时又不影响客户程序使用面向对象的方式进行操作? 本文试图通过一个简单的字符处理的例子,运用重构的手段,一步步带你走进Flyweight模式,在这个过程中我们一同思考.探索.权衡,通过比较而得出好的实现方式,而不

10、Python与设计模式--享元模式

一.网上咖啡选购平台 假设有一个网上咖啡选购平台,客户可以在该平台上下订单订购咖啡,平台会根据用户位置进行线下配送.假设其咖啡对象构造如下: class Coffee: name = '' price =0 def __init__(self,name): self.name = name self.price = len(name)#在实际业务中,咖啡价格应该是由配置表进行配置,或者调用接口获取等方式得到,此处为说明享元模式,将咖啡价格定为名称长度,只是一种简化 def show(self):

设计模式之禅之设计模式-享元模式

一:享元模式定义        --->享元模式(Flyweight Pattern)是池技术的重要实现方式        --->使用共享对象可有效地支持大量的细粒度的对象        --->要求细粒度对象,那么不可避免地使得对象数量多且性质相近,那我们就将些对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic).                ● 内部状态                        内部状态是对象可共享出来的信息,存储在享元对象

C++设计模式编程之Flyweight享元模式结构详解_C 语言

由遇到的问题引出享元模式: 在面向对象系统的设计何实现中,创建对象是最为常见的操作.这里面就有一个问题:如果一个应用程序使用了太多的对象,就会造成很大的存储开销.特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果为没有字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费.例如一个字母"a"在文档中出现了100000 次,而实际上我们可以让这一万个字母"a"共享一个对象,当然因为在不同的位置可能字母"a"有不

详解Java设计模式编程中的Flyweight享元模式的开发结构_java

享元(Flyweight)模式:通过共享技术以便有效的支持大量细粒度的对象. 享元模式在阎宏的<java与模式>中分为单纯享元模式和复合享元模式,复合模式的复合享元是不可以共享的,享元对象能做到共享的关键是区分内蕴态(Internal State)和外蕴态( External State).这两个"蕴态"翻译的太难懂,我不是说翻译的不好,可能是我理解能力差,还是<Design Pattern Elements of Reusable Object-Oriented S

总结JavaScript设计模式编程中的享元模式使用_基础知识

享元模式不同于一般的设计模式,它主要用来优化程序的性能,它最适合解决大量类似的对象而产生的性能问题.享元模式通过分析应用程序的对象,将其解析为内在数据和外在数据,减少对象的数量,从而提高应用程序的性能. 基本知识 享元模式通过共享大量的细粒度的对象,减少对象的数量,从而减少对象的内存,提高应用程序的性能.其基本思想就是分解现有类似对象的组成,将其展开为可以共享的内在数据和不可共享的外在数据,我们称内在数据的对象为享元对象.通常还需要一个工厂类来维护内在数据. 在JS中,享元模式主要有下面几个角色

学习php设计模式 php实现享元模式(flyweight)_php技巧

一.意图运用共享技术有效的支持大量细粒度的对象 享元模式变化的是对象的存储开销二.享元模式结构图 三.享元模式中主要角色抽象享元(Flyweight)角色:此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口.那些需要外蕴状态的操作可以通过调用商业以参数形式传入具体享元(ConcreteFlyweight)角色:实现Flyweight接口,并为内部状态(如果有的话)拉回存储空间.ConcreteFlyweight对象必须是可共享的.它所存储的状态必须是内部的不共享的具体享元(Unsh