【设计模式学习笔记十二】【结构型模式】【享元模式(FlyWeight)】
来源:互联网 发布:ubuntu owncloud 编辑:程序博客网 时间:2024/04/30 02:12
本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.csdn.net/lovelion/article/details/17517213
主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。
我应该理解和掌握的:
1)能够画出这个设计模式的架构框图;
2)能够根据架构框图写出对应的伪代码;
3)这个模式的应用场景,主要优缺点。
1.享元模式
当一个软件系统中产生大量的相同或相似对象时,将会导致运行代价过高,消耗大量内存。比如围棋棋子的设计,假如我们没下一步棋都去new一个对象出来,将会占用大量的内存空间。面对这种情况,享元模式能够很好的解决这个问题,通过共享技术实现相同或相似对象的重用,存放这些共享实例对象的地方称为享元池。我们针对每一个不同的棋子创建一个对象,将他放在享元池中,需要时再从里面取出。
(1)定义
享元模式:运用共享技术有效地支持大量细粒度的对象。系统只使用少量的对象,而这些对象都很相似,状态变化小,可以实现多次复用。又称轻量级模式。
1) 注意
需要注意的是,享元对象能够做到共享的关键是区分了内部状态和外部状态。
a) 内部状态是存储在享元对象内部并且不会随环境改变的状态,内部状态可以共享。如棋子的大小,形状。
b) 外部状态是随环境改变而改变的、不可以共享的状态。如棋子放在棋盘的位置。
c) 区分这两个状态,把具有内部状态的对象存在享元池中,需要时再取;在把取出的享元对象注入不同外部的外部状态,可以得到一系列相似的对象。
2)享元模式结构图
3)参与者
a) Flyweight(抽象享元类):描述一个接口,通过这个接口flyweight可以接受并作用于外部状态;
b) ConcreteFlyweight(具体享元类):实现flyweight接口,并为内部状态增加存储空间;ComcreteFlyweight对象必须是可以共享的,它所存储的状态必须是内部的;即,他必须独立于ConcreteFlyweight对象的场景;
c) UnsharedConcreteFlyweight(非共享具体享元类):并非所有Flyweight子类都需要被共享。不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类时可以直接实例化创建。
d) FlyweightFactory(享元工厂类):用于创建并管理Flyweight对象;当用户请求一个flyweight对象时,FlyweightFactory对象提供一个已经创建的实例或者创建一个(如果不存在的话)。
d) Client(客户端):维持一个对flyweight的引用,计算或存储一个(或多个外部状态)。
e) Coordinartes(外部状态):与外部环境相关,即棋子放置的位置,随时变化,由客户端计算或存贮;把这个外部状态注入到ConcreteFlyweight.上面的结构图没有,请看下面这个结构图:
4)看图写代码
#include<iostream>#include<map>#include<string>using namespace std;/* ** FileName : DecoratorPattern ** Author : lin005 ** Date : 2015/01/29 ** Description : More information, please go to http://blog.csdn.net/amd123456789 *///外部状态,注入给共享元对象,不同坐标得到一系列相似的棋子class Coordinates{public: Coordinates():x(0),y(0){} Coordinates(int a, int b):x(a),y(b){} void setX(int a){x = a;} void setY(int b){y = b;} int getX(){return x;} int getY(){return y;}private: int x; int y;};//Flyweight:抽象共享元类class IgoChessman{public: virtual string getColor() = 0; virtual void display(Coordinates pos){};};//根据颜色生成不同的棋子class ConcreteIgoChessman:public IgoChessman{public: ConcreteIgoChessman(string c):color(c){} string getColor() { return color; } void display(Coordinates pos) { cout<<"the color is "<<getColor()<<";the pos is x = "<<pos.getX()<<"; y = "<<pos.getY()<<endl; }private: string color;};//工厂类维护一个实例列表(也就是享元池),保存所有的共享实例。class IgoChessmanFactory{public: static IgoChessmanFactory* getInstance(); IgoChessman* getIgoChessman(string color);private: static IgoChessmanFactory* _instance; //存放对象,也就是共享元池 map<string, IgoChessman*> m_map;};IgoChessmanFactory* IgoChessmanFactory::_instance = NULL;IgoChessmanFactory* IgoChessmanFactory::getInstance(){ if(_instance == NULL) { _instance = new IgoChessmanFactory(); } return _instance;}IgoChessman* IgoChessmanFactory::getIgoChessman(string color){ //如果找不到棋子,则生成一个,如果有,直接取出 map<string,IgoChessman*>::iterator it = m_map.find(color); IgoChessman *ic = NULL; if(it->second == NULL) { ic = new ConcreteIgoChessman(color); m_map.insert(pair<string, IgoChessman*>(color, ic)); } else { ic = m_map.find(color)->second; } return ic;};//客户端测试int main(int argc, const char * argv[]) { //声明白色,黑色,红色的抽象棋子 IgoChessman *b1,*b2,*b3,*wr; //创建黑色的棋子 b1 = IgoChessmanFactory::getInstance()->getIgoChessman("black"); b2 = IgoChessmanFactory::getInstance()->getIgoChessman("black"); b3 = IgoChessmanFactory::getInstance()->getIgoChessman("black"); //每种棋子注入不同的坐标,也就是外部状态 b1->display(Coordinates(1,2)); b2->display(Coordinates(60,2)); b3->display(Coordinates(1,55)); //这里输出的时指针地址,每个指针的地址都不一样,故指针也会消耗内存,这里只是做验证用 cout<<&(b1)<<" "<<&(b2)<<" "<<&(b3)<<endl; //这里输出的时指针所指向内容的地址,全都一样,指向享元池的对象,这是我们要的结果 cout<<&(*b1)<<" "<<&(*b2)<<" "<<&(*b3)<<endl; //创建白色的棋子 wr = IgoChessmanFactory::getInstance()->getIgoChessman("white"); //注入显示位置 wr->display(Coordinates(100,2)); //查看地址是否一样 cout<<&wr<<" "<<&(*wr)<<endl; wr = IgoChessmanFactory::getInstance()->getIgoChessman("white"); wr->display(Coordinates(1,200)); cout<<&wr<<" "<<&(*wr)<<endl; //创建红色的棋子,指针地址一样,红色棋子的地址一样 wr = IgoChessmanFactory::getInstance()->getIgoChessman("red"); wr->display(Coordinates(10,200)); cout<<&wr<<" "<<&(*wr)<<endl; wr = IgoChessmanFactory::getInstance()->getIgoChessman("red"); wr->display(Coordinates(100,200)); cout<<&wr<<" "<<&(*wr)<<endl; return 0;}
(2)总结
1)优点
a) 极大减少内存中对象的数量,避免相似对象的开销。使得相同相似对象在内存中只保留一份,从而可以节约系统资源,提高系统性能。
b) 享元的外部状态相对独立,不会影响内部状态,从而使得享元对象在不同的环境中共享。
2)缺点
a) 需要分离出外部状态和内部状态,是系统、逻辑编的复杂。
b) 使享元对象的部分状态外部化,可以将这些状态传入对象中。
(3)适用场景
1)一个应用程序使用了大量对象。
2)完全由于使用大量对象,造成很大的存储开销。
3)对象的大多数状态都可以变为外部状态。
4)如果删除对象的外部状态,那么可以用相对较少的共享对象取代多组对象。
5)在享元模式中需要维护一个存储享元对象的享元池,这需要耗费一定的系统资源,因此需要再多次重复使用享元对象的情况下才使用享元模式。
- 【设计模式学习笔记十二】【结构型模式】【享元模式(FlyWeight)】
- 设计模式学习笔记十二(Flyweight享元模式)
- 设计模式学习笔记(十二)——Flyweight享元模式
- 设计模式学习笔记(二十二)—FlyWeight享元模式
- [设计模式笔记]二. 结构型模式--12.Flyweight模式(享元模式)(一)
- [设计模式笔记]二. 结构型模式--12.Flyweight模式(享元模式)(二)
- 设计模式 笔记 享元模式 Flyweight
- C#面向对象设计模式纵横谈 学习笔记12 FlyWeight享元模式(结构型模式)
- 设计模式学习笔记--享元(Flyweight)模式
- 设计模式学习笔记——享元(Flyweight)模式
- 设计模式--结构型模式之六-Flyweight享元
- 设计模式(11)-结构型-享元模式(Flyweight)
- [设计模式-结构型]享元模式(Flyweight )
- 【设计模式基础】结构型模式 - 6 - 享元(Flyweight)
- 设计模式--享元模式FlyWeight(结构型)
- 结构型设计模式---享元模式(Flyweight)
- 设计模式(结构型)之享元模式(Flyweight Pattern)
- 设计模式-结构型-享元模式(Flyweight)
- java多线程之生产者消费者经典问题
- java 操作 vsftp 文件
- 什么是哈希码?
- SSH框架总结(框架分析+环境搭建+实例源码下载)
- initrd.img中的init脚本分析,load_modules()分析
- 【设计模式学习笔记十二】【结构型模式】【享元模式(FlyWeight)】
- UVa 1592 Database ACM解题报告(map和pair的使用)
- APP将会灭亡?
- 每一个程序员需要了解的10个Linux命令
- 定义集合enum时出错
- 21分钟 MySQL 入门教程
- PHP入门基础学习篇(五)
- 计算2对经纬度距离的方法
- 非arc工程导入arc库文件与arc工程导入非arc库文件