概述
一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。
想想我们编辑文档用的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
// 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
// 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;
}
#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
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)
参考:
另外一个围棋的例子: