享元模式flyweight详解精编版.docx
- 文档编号:8271182
- 上传时间:2023-01-30
- 格式:DOCX
- 页数:13
- 大小:19.35KB
享元模式flyweight详解精编版.docx
《享元模式flyweight详解精编版.docx》由会员分享,可在线阅读,更多相关《享元模式flyweight详解精编版.docx(13页珍藏版)》请在冰豆网上搜索。
享元模式flyweight详解精编版
公司内部编号:
(GOOD-TMMT-MMUT-UUPTY-UUYY-DTTI-9018)
享元模式flyweight详解
享元模式
模式描述:
享元模式以共享的方式高效地支持大量的细粒度对象。
享元对象能做到共享的关键是区分内蕴状态和外蕴状态:
内蕴状态(InternalState)是存储在享元对象内部并且不会随环境改变而改变。
因此内蕴状态并可以共享。
外蕴状态(ExternalState)是随环境改变而改变的、不可以共享的状态。
享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。
外蕴状态与内蕴状态是相互独立的。
名称:
享元模式(Flyweight),Flyweight在拳击比赛中指最轻量级,即"蝇量级",有些作者翻译为"羽量级"。
这里使用"享元模式"更能反映模式的用意。
计算模型:
享元模式可以分为单纯享元模式和复合享元模式:
一、单纯享元模式结构图:
单纯享元模式构成说明:
1)抽象享元(Flyweight)角色:
此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。
那些需要外蕴状态(ExternalState)的操作可以通过调用商业方法以参数形式传入。
2)具体享元(ConcreteFlyweight)角色:
实现抽象享元角色所规定的接口。
如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
3)享元工厂(FlyweightFactory)角色:
本角色负责创建和管理享元角色。
本角色必须保证享元对象可以被系统适当地共享。
当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。
如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
4)客户端(Client)角色:
需要维护一个对所有享元对象的引用;需要自行存储所有享元对象外蕴状态。
二、复合享元模式结构图:
复合享元模式构成说明:
1)抽象享元角色:
此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口。
那些需要外蕴状态(ExternalState)的操作可以通过方法的参数传入。
抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
2)具体享元(ConcreteFlyweight)角色:
实现抽象享元角色所规定的接口。
如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。
有时候具体享元角色又叫做单纯具体享元角色,因为复合享元角色是由单纯具体享元角色通过复合而成的。
3)复合享元(UnsharableFlyweight)角色:
复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。
复合享元角色又称做不可共享的享元对象。
4)享元工厂(FlyweightFactoiy)角色:
本角色负责创建和管理享元角色。
本角色必须保证享元对象可以被系统适当地共享。
当一个客户端对象请求一个享元对象的时候,享元工厂角色需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
5)客户端(Client)角色:
本角色还需要自行存储所有享元对象的外蕴状态。
配置约束:
享元模式应用的条件如下:
1.一个系统有大量的对象。
2.这些对象耗费大量的内存。
3.这些对象的状态中的大部分都可以外部化。
4.这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
5.软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
特点:
享元模式的优点:
大幅度地降低内存中对象的数量。
享元模式的缺点:
1:
享元模式使得系统更加复杂。
为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
2:
享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
总结:
享元模式一般是解决系统性能问题的,所以经常用于底层开发,在项目开发中并不常用。
不变式:
1.存在一个享元工厂角色,负责创建和管理享元角色。
2.存在一个抽象享元角色,作为所有具体享元类的超类,为这些类规定出需要实现的公共接口。
3.存在一个或多个具体享元角色,实现抽象享元角色所规定的接口。
代码:
单纯享元模式:
///
///"Flyweight"
///
abstractclassFlyweight
{
//
Methods
///
///抽象享元对象的商业方法
///
///
name="extrinsicstate">外蕴状态
abstractpublicvoidOperation(intextrinsicstate);
}
///
///"ConcreteFlyweight"
///
classConcreteFlyweight:
Flyweight
{
privatestringintrinsicstate="A";
//
Methods
overridepublicvoidOperation(intextrinsicstate)
{
Console.WriteLine("ConcreteFlyweight:
intrinsicstate{0},extrinsicstate{1}",intrinsicstate,
extrinsicstate);
}
}
///
///"FlyweightFactory"
///
classFlyweightFactory
{
//
Fields
privateDictionary
newDictionary Flyweight>(); privatestaticreadonlyFlyweightFactoryinstance= newFlyweightFactory(); /// ///Constructors /// privateFlyweightFactory() { } // Methods /// ///从享元工厂中生产出一个具体的享元对象 /// /// name="key">内蕴状态 /// publicFlyweightGetFlyweight(stringkey) { return((Flyweight)flyweights[key]); } /// ///享元工厂单例方法 /// /// publicstaticFlyweightFactorySingleton() { returnFlyweightFactory.instance; } /// ///向享元工厂对象增加一个享元对象 /// /// name="sKey">内蕴状态 /// name="_Flyweight">具体享元对象 publicvoidAddFlyweight(stringsKey,Flyweight_Flyweight) { flyweights.Add(sKey,_Flyweight); } publicFlyweightfactory(stringsKey) { if(flyweights.ContainsKey(sKey)) { returnthis.GetFlyweight(sKey); } else { this.AddFlyweight(sKey, newConcreteFlyweight()); returnthis.GetFlyweight(sKey); } } } /// ///测试代码 /// classTest { publicstaticvoidmain() { // 初始化外蕴状态值 intextrinsicstate=22; //享元工厂对象使用单例 FlyweightFactoryf=FlyweightFactory.Singleton(); //调用过程 //向享元工厂对象请求一个内蕴状态为"X"的单纯享元对象 Flyweightfx=f.factory("X"); //调用X的商业方法,X的外蕴状态值为21 fx.Operation(--extrinsicstate); Flyweightfy=f.factory("Y"); fy.Operation(--extrinsicstate); Flyweightfz=f.factory("Z"); fz.Operation(--extrinsicstate); } } publicinterfaceFlyweight{ publicvoidoperation(Stringstate); } publicclassConcerteFlyweightimplementsFlyweight{ //内蕴状态 privateCharacterintrinsicState=null; //传进来的参数属于外晕状态 publicConcerteFlyweight(Characterstate){ this.intrinsicState=state; } publicvoidoperation(Stringstate){ } } publicclassFlyweightFactory{ privateHashMapflies=newHashMap(); privateFlyweightfly; publicFlyweightFactory(){ } //字体样式 publicFlyweightfactory(Characterstate){ if(flies.containsKey(state)){ return(Flyweight)flies.get(state); }else{ fly=newConcerteFlyweight(state); flies.put(state,fly); returnfly; } } } publicclassClient{ publicstaticvoidmain(String[]args){ FlyweightFactoryfactory=newFlyweightFactory(); Flyweightfly=factory.factory(newCharacter('a')); fly.operation("罗马字符"); fly.operation("新罗马字符"); fly=factory.factory(newCharacter('b')); fly.operation("阿拉伯字符"); } } 复合享元模式: publicinterfaceFlyweight{ publicvoidoperation(Stringstate); } publicclassConcreteFlyweightimplementsFlyweight { privateCharacterintrinsicState=null; //构造子,内蕴状态作为参数传入 publicConcreteFlyweight(Characterstate) { this.intrinsicState=state; } //外蕴状态作为参数传入方法 publicvoidoperation(Stringstate) { } } publicclassConcreteCompositeFlyweightimplementsFlyweight{ privateHashMapflies=newHashMap(10); privateFlyweightflyweight; publicConcreteCompositeFlyweight(){} //增加一个新的单纯享元对象到聚集中 publicvoidadd(Characterkey,Flyweightfly) { flies.put(key,fly); } //外蕴状态作为参数传入到方法中 publicvoidoperation(StringextrinsicState) { Flyweightfly=null; for(Iteratorit=flies.entrySet().iterator();it.hasNext();) { Map.Entrye=(Map.Entry)it.next(); fly=(Flyweight)e.getValue(); fly.operation(extrinsicState); } } } publicclassFlyweightFactory { privateHashMapflies=newHashMap(); publicFlyweightFactory(){} //单纯享元工厂方法,所需状态以参量形式传入 publicFlyweightfactory(Characterstate) { if(flies.containsKey(state)) { return(Flyweight)flies.get(state); }else{ Flyweightfly=newConcreteFlyweight(state); flies.put(state,fly); returnfly; } } //符合享元工厂方法,所需状态以参量形式传入,这个参量巧好可以使用string类型 publicFlyweightfactory(StringcompositeState) { ConcreteCompositeFlyweightcompositeFly=newConcreteCompositeFlyweight(); intlength=compositeState.length(); Characterstate=null; for(inti=0;i { state=newCharacter(compositeState.charAt(i)); compositeFly.add(state,this.factory(state)); } returncompositeFly; } } publicclassClient{ /** *@paramargs */ publicstaticvoidmain(String[]args){ FlyweightFactoryfactory=newFlyweightFactory(); Flyweightfly=(Flyweight)factory.factory("abac"); fly.operation("罗马字符"); } } /********************************* *设计模式--享元模式实现 *C++语言 *Author: WangYong ********************************/ #include #include #include #include usingnamespacestd; classFlyweight { public: virtual~Flyweight(){} virtualvoidOperation(conststring&extrinsicState){} stringGetIntrinsicState(){returnthis->_intrinsicState;} protected: Flyweight(stringintrinsicState){this->_intrinsicState=_intrinsicState;} private: string_intrinsicState; }; classConcreteFlyweight: publicFlyweight { public: ConcreteFlyweight(stringintrinsicState): Flyweight(intrinsicState) {cout<<"ConcreteFlyweightBuild...."< ~ConcreteFlyweight(){} voidOperation(conststring&extrinsicState) { cout<<"ConcreteFlyweight: 内蕴"< <<"ConcreteFlyweight: 外蕴"< } }; classFlyweightFactory { public: FlyweightFactory(){} ~FlyweightFactory(){} Flyweight*GetFlyweight(conststring&key) { vector : iteratorit=_fly.begin(); for(;it! =_fly.end();it++) { if((*it)->GetIntrinsicState()==key) cout<<"alreadycreatedbyusers..."< return*it; } Flyweight*fn=newConcreteFlyweight(key); _fly.push_back(fn); returnfn; } private: vector }; intmain() { FlyweightFactory*fc=newFlyweightFactory(); Flyweight*fw1=fc->GetFlyweight("hello"); Flyweight*fw2=fc->GetFlyweight("world! "); Flyweight*fw3=fc->GetFlyweight("hello"); } 典型应用: 一、享元模式在编辑器系统中大量使用。 一个文本编辑器往往会提供很多种字体,而通常的做法就是将每一个字母做成一个享元对象。 享元对象的内蕴状态就是这个字母,而字母在文本中的位置和字模风格等其他信息则是外蕴状态。 比如,字母a可能出现在文本的很多地方,虽然这些字母a的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。 这样一来,字母对象就可以在整个系统中共享。 二、享元模式在.NETFramework中的应用。 String无论在.NET还是Java中,都是一个特殊的引用对象。 我们可以试想,出现了这样一段代码: Strings=”Helloworld”; Strings1=”Helloworld”; 那么是不是每次都要重新的去申请一块内存,然后去保存这个字符串呢那么这样的话是不是会效率很低呢因为我们知道,字符串在实际使用中往往都是非常短暂的。 他们通常是被读出来之后,便直接展示给了客户。 然后这个字符串的生命结束,变成垃圾。 在.NET和Java中,String都被以不变模式来进行设计。 我们来简单的分析一下String的驻留机制: 在CLR被加载之后,就会在SystemDomain的托管堆中去建立一个HashTable来维护String。 于是模拟代码如下: (伪代码) Hashtabletable; if(! table.Contains("Helloworld")) { table.Add("Helloworld",&(newString("Helloworld"))); } return*(table["Helloworld"]); 也就是说,我是在模拟一个strings=”Helloworld”的过程。 过程是,首先,他先去找Hashtable中目前是否存有Key为”Helloworld”的项。 如果不存在,那么就分配一块堆内存,存储这字符串,然后将地址作为Value,存储在Hashtable中。 如果存在的话,那么便直接找到该字符串所对应的地址,然后取出地址中的值。 用一个Hashtable来控制String对象的数量。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 模式 flyweight 详解 精编