您好,欢迎访问三七文档
?php/***享元模式*采用一个共享来避免大量拥有相同内容对象的开销。这种开销中最常见、直观的就是内存的损耗。享元模式以共享的方式高效的支持大量的细粒度对象。在名字和定义中都体现出了共享这一个核心概念,那么怎么来实现共享呢?要知道每个事物都是不同的,但是又有一定的共性,如果只有完全相同的事物才能共享,那么享元模式可以说就是不可行的;因此我们应该尽量将事物的共性共享,而又保留它的个性。为了做到这点,享元模式中区分了内蕴状态和外蕴状态。内蕴状态就是共性,外蕴状态就是个性了。注:共享的对象必须是不可变的,不然一变则全变(如果有这种需求除外)。内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的;外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。在每个具体的环境下,客户端将外蕴状态传递给享元,从而创建不同的对象出来。*/classCD//共享的部分{private$_title=null;private$_artist=null;publicfunctionsetTitle($title){$this-_title=$title;}publicfunctiongetTitle(){return$this-_title;}publicfunctionsetArtist($artist){$this-_artist=$artist;}publicfunctiongetArtist($artist){return$this-_artist;}}classArtist{private$_name;publicfunction__construct($name){echoconstruct.$name.br/;$this-_name=$name;}publicfunctiongetName(){return$this-_name;}}classArtistFactory{private$_artists=array();publicfunctiongetArtist($name){if(isset($this-_artists[$name])){return$this-_artists[$name];}else{$objArtist=newArtist($name);$this-_artists[$name]=$objArtist;return$objArtist;}}}$objArtistFactory=newArtistFactory();$objCD1=newCD();$objCD1-setTitle(title1);$objCD1-setArtist($objArtistFactory-getArtist('artist1'));$objCD2=newCD();$objCD2-setTitle(title2);$objCD2-setArtist($objArtistFactory-getArtist('artist2'));$objCD3=newCD();$objCD3-setTitle(title3);$objCD3-setArtist($objArtistFactory-getArtist('artist1'));享元模式英文称为“FlyweightPattern”,我非常感谢将FlyweightPattern翻译成享元模式的那位强人,因为这个词将这个模式使用的方式明白得表示了出来;如果翻译成为羽量级模式或者蝇量级模式等等,虽然可以含蓄的表现出使用此模式达到的目的,但是还是没有抓住此模式的关键。享元模式的定义为:采用一个共享来避免大量拥有相同内容对象的开销。这种开销中最常见、直观的就是内存的损耗。享元模式以共享的方式高效的支持大量的细粒度对象。在名字和定义中都体现出了共享这一个核心概念,那么怎么来实现共享呢?要知道每个事物都是不同的,但是又有一定的共性,如果只有完全相同的事物才能共享,那么享元模式可以说就是不可行的;因此我们应该尽量将事物的共性共享,而又保留它的个性。为了做到这点,享元模式中区分了内蕴状态和外蕴状态。内蕴状态就是共性,外蕴状态就是个性了。注:共享的对象必须是不可变的,不然一变则全变(如果有这种需求除外)。内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的;外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。在每个具体的环境下,客户端将外蕴状态传递给享元,从而创建不同的对象出来。至于怎样来维护客户端保持的外蕴状态和享元内部保持的内蕴状态的对应关系,你先不用担心这个问题,我们后面会涉及到的。我们引用《Java与模式》中的分类,将享元模式分为:单纯享元模式和复合享元模式。在下一个小节里面我们将详细的讲解这两种享元模式。三、结构先从简单的入手,看看单纯享元模式的结构。1)抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。2)具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。3)享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!4)客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。来用类图来形象地表示出它们的关系吧(对类图的了解可以参看我关于类图的blog)。怎么咋看咋像简单工厂模式呢!没错,可以说结构型的单纯享元模式和创建型的简单工厂模式实现上非常相似,但是它的重点或者用意却和工厂模式截然不同。工厂模式的使用主要是为了使系统不依赖于实现得细节(见《深入浅出工厂模式》);而在享元模式的主要目的如前面所述:采用共享技术来避免大量拥有相同内容对象的开销。正所谓“旧瓶装新酒”阿!再来看看复合享元模式的结构。1)抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。2)具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。3)复合享元角色:它所代表的对象是不可以共享的,并且可以分解成为多个单纯享元对象的组合。4)享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键!5)客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。统比一下单纯享元对象和复合享元对象,里面只多出了一个复合享元角色,但是它的结构就发生了很大的变化。我们还是使用类图来表示下:你也许又纳闷了,这个也似曾相逢!单看左半部,和简单工厂模式类似;再看右半部,怎么这么像合成模式呢(请参看关于合成模式的文章或者期待我的《深入浅出合成模式》)!合成模式用在此处就是为了将具体享元角色和复合享元角色同等对待和处理,通过将享元模式与合成模式组合在一起,可以确保复合享元中所包含的每个单纯享元都具有相同的外蕴状态,而这些单纯享元的内蕴状态往往是不同的。四、举例这里就以去餐馆吃饭为例详细的说明下享元模式的使用方式。去菜馆点菜吃饭的过程大家一定都是轻车熟路了,这里就不赘述。在例子中我使用了一个list来存放外蕴状态和内蕴状态的对应关系,而且提供了查询每个客人点菜情况的方法。内蕴状态在这里代表了菜肴的种类,而外蕴状态就是每盘菜肴的点菜人。A让我们先来看看单纯享元模式的实现吧。先看下抽象享元角色的定义:interfaceMenu{//规定了实现类必须实现设置内外关系的方法publicvoidsetPersonMenu(Stringperson,Listlist);//规定了实现类必须实现查找外蕴状态对应的内蕴状态的方法publicListfindPersonMenu(Stringperson,Listlist);}这便是具体享元角色了:classPersonMenuimplementsMenu{privateStringdish;//在构造方法中给内蕴状态附值publicPersonMenu(Stringdish){this.dish=dish;}publicsynchronizedvoidsetPersonMenu(Stringperson,Listlist){list.add(person);list.add(dish);}publicListfindPersonMenu(Stringperson,Listlist){ListdishList=newArrayList();Iteratorit=list.iterator();while(it.hasNext()){if(person.equals((String)it.next()))dishList.add(it.next());}returndishList;}}享元工厂角色,这可是关键所在,大家注意看!classFlyweightFactory{privateMapmenuList=newHashMap();privatestaticFlyweightFactoryfactory=newFlyweightFactory();//这里还使用了单例模式,来使工厂对象只产生一个工厂实例privateFlyweightFactory(){}publicstaticFlyweightFactorygetInstance(){returnfactory;}//这就是享元模式同工厂模式的不同所在!!publicsynchronizedMenufactory(Stringdish){//判断如果内蕴状态已经存在就不再重新生成,而是使用原来的,否则就重新生成if(menuList.containsKey(dish)){return(Menu)menuList.get(dish);}else{Menumenu=newPersonMenu(dish);menuList.put(dish,menu);returnmenu;}}//来验证下是不是真的少产生了对象publicintgetNumber(){returnmenuList.size();}}我们使用客户程序来试验下吧。classClient{privatestaticFlyweightFactoryfactory;publicstaticvoidmain(String[]args){Listlist1=newArrayList();factory=FlyweightFactory.getInstance();Menulist=factory.factory(尖椒土豆丝);list.setPersonMenu(ai92,list1);list=factory.factory(红烧肉);list.setPersonMenu(ai92,list1);list=factory.factory(地三鲜);list.setPersonMenu(ai92,list1);list=factory.factory(地三鲜);list.setPersonMenu(ai92,list1);list=factory.factory(红焖鲤鱼);list.setPersonMenu(ai92,list1);list=factory.factory(红烧肉);list.setPersonMenu(ai921,list1);list=factory.factory(红焖鲤鱼);list.setPersonMenu(ai921,list1);list=factory.factory(地三鲜);list.setPersonMenu(ai921,list1);System.out.println(factory.getNumber());Listlist2=list.findPersonMenu(ai921,list1);Iteratorit=list2.iterator();while(it.hasNext()){Syste
本文标题:享元模式
链接地址:https://www.777doc.com/doc-5906084 .html