C++设计模式---享元模式----浪费可耻,节俭光荣-阿里云开发者社区

开发者社区> 云原生> 正文

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
  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
  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
  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
  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

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
云原生
使用钉钉扫一扫加入圈子
+ 订阅

云原生时代,是开发者最好的时代

其他文章