`
java苹果+番茄
  • 浏览: 67959 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

亨元(Flyweight Pattern)模式【结构模式第三篇】

阅读更多
亨元(Flyweight Pattern)模式
1、亨元模式的用意
亨元模式是对象的结构模式。亨元模式以共享的方式高效地支持大量的细粒度对象。
亨元模式能做到共享的关键是区分内蕴状态和外蕴状态

一个内蕴状态是存储在亨元对象内部的,并且是不会随环境改变而有所不同的。因此,一个亨元可以具有内蕴状态并可以共享。

一个外蕴状态是随环境改变而改变的、不可以共享的状态。亨元对象的外蕴状态必须由客户端保存,并在亨元对象被创建之后,
在需要使用的时候再传入到亨元对象内部。

外蕴状态不可以影响亨元对象的内蕴状态的,它们是相互独立的。

2、亨元模式的种类
根据所涉及的亨元对象的北部表象,亨元模式可以分为单纯亨元模式和复合亨元模式两种形式。

3、亨元模式的实现:
1)单纯亨元模式涉及的角色
1-抽象亨元角色:此角色是所有的具体亨元类的超类,为这些规定出需要实现的公共接口,那些需要外蕴状态的操作
   可以通过方法的参数传入。抽象亨元的接口使得亨元变得可能,但是并不强制子类实行共享,因此并非所有的亨元
   对象都是可以共享的
2-具体亨元角色:实现抽象亨元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
   亨元对象的内蕴状态必须与对象所处的周围环境无关,从而使得亨元对象可以在系统内共享。有时候具体亨元角色
   又叫做单纯具体亨元角色,因为复合亨元角色是由单纯具体亨元角色通过复合而成的
3-复合亨元角色:复合亨元角色所代表的对象是不可以共享的,但是一个复合亨元对象可以分解成为多个本身是单纯亨元
   对象的组合。复合亨元角色又称做不可共享的亨元对象。
4-亨元工厂角色:本角色负责创建和管理亨元角色。本角色必须保证亨元对象可以被系统适当地共享。
   当一个客户端对象请求一个亨元对象的时候,亨元工厂角色需要检查系统中是否已经有一个符合要求的亨元对象,
   如果已经有了,亨元工厂角色就应当提供这个已有的亨元对象;如果系统中没有一个适当的亨元对象的话,
   亨元工厂角色就应当创建一个新的合适的亨元对象。
5-客户端角色:本角色还需要自行存储所有亨元对象的外蕴状态。

//抽象亨元角色
			public abstract class Flyweight{
				public abstract void operation(String state);
			}
			
			//具体亨元角色
			具体亨元角色的主要责任:
				1)实现了抽象亨元角色所声明的接口,也就是operation()方法。operation()方法 接收一个外蕴状态作为参量。
				2)为内蕴状态提供存储空间,在本实现中就是intrinsicState属性。亨元模式本身对内蕴状态的存储类型并无要求
				   这里的内蕴状态是Character类型,是为了给符合亨元的内蕴状态选做String类型提供方便。
			public class ConcreteFlyweight extends Flyweight{
				private Character intrinsicState = null;
				
				public ConcreteFlyweight(Character state){
					this.intrinsicState = state;
				}
				
				//外蕴状态作为参量传入到方法中
				public void operation(String state){
					System.out.print("\nInternal State = " + intrinsicState + "Extrinsic State = " +
					 state);
				}
			}
			
			//具体复合亨元角色
			具体复合亨元角色的责任:
				1)复合亨元对象是由单纯的亨元对象通过复合而成,因此它提供了add()这样的聚集管理方法。
				   由于一个复合亨元对象具有不同的聚集元素,这些聚集元素在复合亨元对象被创建之后加入,这本身就意味着
				   亨元对象的状态是会改变的,因此复合亨元对象是不能共享的。
				2) 复合亨元角色实现了抽象亨元角色所规定的接口, 也就是operation()方法。这个方法有一个参量,
				   代表复合亨元对象的外蕴状态,。一个复合亨元对象的所有单纯亨元对象元素的外蕴状态都是与复合亨元对象的
				   外蕴状态相等的,而一个复合亨元对象所含有的单纯亨元对象的内蕴状态一般是不相等的,不然就没有使用价值了。
			
			import java.util.Map;
			import java.util.HashMap;
			import java.util.Iterator;
			
			public class ConcreteCompositeFlyweight extends Flyweight{
				private HashMap flies = new HashMap(10);
				private Flyweight flyweight;
				
				public ConcreteCompositeFlyweight(){}
				
				//增加一个新的单纯亨元对象到聚集中
				public void add(Character key, Flyweight fly){
					flies.put(key,fly);
				}
				
				//外蕴状态作为参量传入到方法中
				public void operation(String extrinsicState){
					Flyweight fly = null;
					for(Iterator it = flies.entrySet().iterator()); it.hasNext();){
						Map.Entry e = (Map.Entry)it.next();
						fly = (Flyweight)e.getValue();
						fly.operation(extrinsicState);
					}
					
				}
			}
			
			//亨元工厂角色
			import java.util.Map;
			import java.util.HashMap;
			import java.util.Iterator;
			
			public class FlyweightFactory{
				private HashMap flies = new HashMap();
				
				public FlyweightFactory(){}
				
				//复合亨元工厂方法,所需状态以参量形式传入,这个参量恰好可以使用String类型
				public Flyweight factory(String compositeState){
					ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();
					int length = compositeState.length();
					Character state = null;
					for(int i = 0; i < length; i ++){
						state = new Character(compositeState.charAt(i));
						System.out.println("factory(" + state +")");
						compositeFly.add(state,this.factory(state));
					}
					return compositeFly;
				}
				
				//单纯亨元工厂方法
				public Flyweight factory(Character state){
					//检查具有此状态的亨元是否已经存在
					if(flies.containsKey(state)){
						//具有此状态的亨元已经存在,因此直接将它返回
						retun (Flyweight)flies.get(state);
					}else{
						//具有此状态的亨元不存在,因此创建新实例
						Flyweight fly = new ConcreteFlyweight(state);
						//将实例存储到聚集中
						flies.put(state,fly);
						//将实例返回
						return fly;
					}
				}
				
				public void checkFlyweight(){
					Flyweight fly;
					int i = 0;
					System.out.println("\n==========CheckFlyweight()==============");
					for(Iterator it = flies.entrySet().iterator(); it.hasNext();){
						Map.Entry e = (Map.Entry) it.next();
						System.out.println("Item" + (++i) + ";" + e.getKey());
					}
					System.out.println("\n==========CheckFlyweight()==============");
				}
			}


4、模式的实现
1)使用不变模式实现亨元角色
   亨元模式里的亨元对象不一定非得是不变对象,但是很多的亨元对象确实被设计成了不变对象。
   由于不变对象的状态之后就不再变化,因此不变对象满足亨元模式对亨元对象的要求。

2)使用备忘录模式实现亨元工厂角色
   亨元工厂负责维护一个表,通过这个表把很多全同的实例与代表它们的一个对象联系起来。这就是备忘录模式的应用。

3)使用单例模式实现亨元工厂角色
   系统往往只需要一个亨元工厂的实例,所以亨元工厂可以设计成为单例模式。

 在单纯的共享模式中使用单例模式实现共享工厂角色
		   import java.util.Map;
		   import java.util.HashMap;
		   import java.util.Iterator;
		   public class FlyweightFactorySingleton{
		   	private HashMap flies = new HashMap();
		   	private static FlyweightFactorySingleton myself = new FlyweightFactorySingleton();
		   	
		   	private FlyweightFactorySingleton(){}
		   	
		   	public static FlyweightFactorySingleton getInstance(){
		   		return myself;
		   	}
		   	
		   	//工厂方法,向外界提供含有指定内蕴状态的对象
		   	public synchronized Flyweight factory(Character state){
		   		//检查具有此状态的亨元是否已经存在
		   		if(flies.containsKey(state)){
		   			//具有此状态的亨元对象已经存在,因此直接返还此对象
		   			return (Flyweight)flies.get(state);
		   		}else{
		   			Flyweight fly = new ConcreteFlyweight(state);
		   			flies.put(state,fly);
		   			return fly
		   		}
		   	}
		   	
		   	//辅助方法,打印所有已经创建的亨元对象清单
		   	public void checkFlyweight(){
		   		Flyweight fly;
		   		int i = 0;
		   		System.out.println("\n===========checkFlyweight===============");
		   		for(Iterator it = flies.entrySet().iterator(); it.hasNext();){
		   			Map.Entry e = (Map.Entry)it.next();
		   			System.out.println("Item" + (++i) + ":" + e.getKey());
		   		}
		   		System.out.println("\n===========checkFlyweight===============");
		   	}
		   	
		   }
		   
		   //客户端代码
		   public class ClientSingleton{
		   	private static FlyweightFactorySingleton factory;
		   	
		   	public static void main(String args[]){
		   		factory = FlyweightFactorySingleton.getInstance();
		   		Flyweight fly = factory.factory(new Character('a'));
		   		fly.operation("First Call");
		   		fly = factory.factory(new Character('b'));
		   		fly.operation("Second call");
		   		Flyweight fly = factory.factory(new Character('a'));
		   		fly.operation("Third Call");
		   		factory.checkFlyweight();
		   		
		   	}
		   }
		   
		   //将一个共享工厂角色用单例模式实现
		   import java.util.Map;
		   import java.util.HashMap;
		   import java.util.Iterator;
		   
		   public class FlyweightFactorySingleton{
		   	private static FlyweightFactorySingleton myself = new FlyweightFactorySingleton();
		   	private HashMap flies = new HashMap();
		   	private Flyweight inkFlyweight;
		   	
		   	private FlyweightFactorySingleton(){}
		   	
		   	public static FlyweightFactorySingleton getInstance(){
		   		return new FlyweightFactorySingleton();
		   	}
		   	
		   	public Flyweight factory(String complexState){
		   		ConcreteCompositeFlyweight complexFly = new ConcreteCompositeFlyweight();
		   		int length = complexState.length();
		   		Character state = null;
		   		
		   		for(int i = 0; i < length; i ++){
		   			state = new Character(complexState.charAt(i));
		   			System.out.println("factory(" + state + ")");
		   			complexFly.add(state,this.factory(state));
		   		}
		   		return complexFly;
		   	}
		   	
		   	public synchronized Flyweight factory(Character state){
		   		//检查具有此状态的亨元是否已经存在
		   		if(flies.containsKey(state)){
		   			return (Flyweight)flies.get(state);
		   		}else{
		   			Flyweight fly = new ConcreteFlyweight(state);
		   			
		   			flies.put(state,fly);
		   			return fly;
		   		}
		   	}
		   	
		   	public void checkFlyweight(){
		   		Flyweight fly;
		   		int i = 0;
		   		System.out.println("\n===========checkFlyweight===============");
		   		for(Iterator it = flies.entrySet().iterator(); it.hasNext();){
		   			Map.Entry e = (Map.Entry)it.next();
		   			System.out.println("Item" + (++i) + ":" + e.getKey());
		   		}
		   		System.out.println("\n===========checkFlyweight===============");
		   	}
		   }
		   
		   //一个应用亨元模式的咖啡摊例子
		   
		   //抽象亨元角色,serve()它没有参量是因为没有外蕴状态
		   public abstract class Order{
		   	//将咖啡卖客人
		   	public abstract void serve();
		   	//返还咖啡的名字	
		   	public abstract String getFlavor();	
		   }
			
			
		//具体亨元角色
		public class Flavor extends Order{
			private String flavor;
			
			public Flavor(String flavor){
				this.flavor = flavor;
			}
			
			public String getFlavor(){
				return this.flavor;
			}
			
			//将咖啡卖给客人
			public void serve(){
				System.out.println(System.out.println("Serving flavor " + flavor);
			}
		}
		
		//工厂角色
		public class FlavorFactory{
			private Order[] flavors = new Flavor[10];
			private int ordersMade = 0;
			private int totalFlavors = 0;
			
			//工厂方法,根据所需的风味提供咖啡
			public Order getOrder(String flavorToGet){
				if(ordersMade > 0){
					for(int i  = 0 ; i < ordersMade; i ++){
						if(flavorToGet.equals(flavors[i].getFlavor())){
							return flavors[i];
						}
					}
				}
				flavors[ordersMade] = new Flavor(flavorToGet);
				totalFlavors++;
				return flavors[ordersMade++];
			}
			
			//辅助方法,返还创建过的风味对象的个数
			public int getTotalFlavorsMade(){
				return totalFlavors;
			}
		}
		
		//客户端代码,代表咖啡摊侍者
		public class ClientFlavor{
			private static Order[] flavors = new Flavor[20];
			private static int ordersMade = 0;
			private static FlavorFactory flavorFactory;
			
			//提供一杯咖啡
			private static void takeOrders(String aFlavor){
				flavors[ordersMade++] = flavorFactory.getOrder(aFlavor);
			} 
			
			public static void main(String args[]){
				flavorFactory = new FlavorFactory();
				
				takeOrders("Black Coffee");
				takeOrders("Capucino");
				takeOrders("Espresso");
				takeOrders("Espresso");
				takeOrders("Capucino");
				takeOrders("Capucino");
				takeOrders("Black Coffee");
				takeOrders("Espresso");
				takeOrders("Capucino");
				
				//将所创建的对象卖给客人
				for(int i = 0; i < ordersMade; i ++){
					flavors[i].serve();
				}
				System.out.println("\nTotal teaFlavor objects made: " + 
								flavorFactor.getTotalFlavorsMade() );
			}
		}
		
		//如果这个例子再大点,可以增加一个外蕴状态,也就是说可以增加桌子号,建立一个桌子类,将桌子号作为
		参数传给serve(Table table).

5、亨元模式的使用情况
当以下所有的条件都满足时,可以考虑使用亨元模式:
(1)一个系统有大量的对象。
(2)这些对象耗费大量的内存
(3)这些对象的状态中大部分都可以外部化
(4)这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
(5)软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
应当在有足够多的亨元实例可供共享时才值得使用亨元模式。

6、怎样做到共享
一个亨元对象之所以可以被很多的用户端共享,是因为它只含有可以共享的状态,而没有不可以共享的状态,
这就是使用亨元模式的前提。

要做到符合亨元模式这一点,需要分两步走:
(1)将可以共享的状态和不可以共享的状态从此常规类中区分开来,将不可共享的状态从类里剔除出去。
那些对所有客户端都去相同的值的状态是可以共享的状态;而那些对不同的客户端有不同值的状态是不可以共享的状态

(2)这个类的创建过程必须由一个工厂对象加以控制。
    这个工厂对象应当使用一个内部列表保存所有的已经创建出来的对象。当客户端请求一个新的对象时,
    工厂对象首先检查列表,看是否已经有一个对象。如果已经有了,就直接返还此对象,如果没有就创建一个新对象。
亨元模式要求将可以共享的状态设置为内蕴状态,而将不可以共享的状态设置成外蕴状态,将它们外部化。

7、亨元模式的优缺点
亨元模式的优点在于它大幅度降低内存中对象的数量。但是,它做到这一点所付出的代价也是很高的:
(1)亨元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化
(2)亨元模式将亨元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
分享到:
评论

相关推荐

    设计模式(C#)之享元模式(Flyweight Pattern)

    本篇文章将深入探讨享元模式的基本概念、结构以及在C#中的实现方式。 一、享元模式的概念 享元模式是一种轻量级的内存优化策略,其核心思想是区分内部状态和外部状态。内部状态是对象可以共享的部分,不随环境改变...

    结构型模式之共享元模式(Flyweight)

    6共享元模式(Flyweight) 用意:以共享的方式高效地支持大量的细粒度对象

    c++-设计模式之享元模式(Flyweight)

    享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建大量小对象所带来的内存开销。通过共享对象,享元模式能够有效地支持大量细粒度的对象,减少内存使用并提高性能。它常用于需要大量重复对象的场景...

    C#设计模式之Flyweight

    "Flyweight"(享元)设计模式是一种结构型模式,其核心目的是为了有效地支持大量细粒度对象的创建和使用,通过共享已经存在的对象来减少内存消耗,提高系统性能。在C#中,Flyweight模式尤其适用于那些内部状态可共享...

    享元模式flyweight

    享元模式(Flyweight Pattern)是一种结构型设计模式,它能有效地减少系统中对象的数量,从而降低内存消耗,提高性能。这种模式通过共享大量相似对象的内部状态来达到这一目标,而只保留对象的外部状态在外部管理。...

    C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式) (Level 300)

    享元模式是面向对象设计中的一种结构型模式,它的主要目的是通过共享大量相似对象来减少内存的使用,提高系统的性能。在C#编程语言中,我们可以利用享元模式来优化那些具有大量实例但大部分状态可以共享的对象。在这...

    学习php设计模式 php实现享元模式(flyweight)

    享元模式(Flyweight Pattern)是软件设计中的一种结构型设计模式,它通过共享技术来支持大量细粒度的对象,以此来降低内存中对象的数量。在PHP中实现享元模式,可以帮助我们优化程序性能,特别是在对象数目过多时,...

    设计模式之轻量级Flyweight

    通过分析和运行这些测试代码,我们可以更深入地理解享元模式的工作原理及其在性能优化方面的效果。 总之,Flyweight模式是一种有效的设计策略,通过共享对象来节省资源,尤其适用于处理大量相似对象的情况。理解并...

    C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式)

    C#面向对象设计模式纵横谈(12):Flyweight 享元模式(结构型模式)

    C#版 24种设计模式

    适配器模式(Adapter Pattern) 提供者模式(Provider Pattern) 外观模式(Facade Pattern) 享元模式(Flyweight Pattern) 原型模式(Prototype Pattern) 责任链模式(Chain of Responsibility Pattern) 中介者模式...

    C#设计模式_设计模式_C#_

    享元模式(Flyweight Pattern) 12. 代理模式(Proxy Pattern) 行为型: 13. 模板方法(Template Method) 14. 命令模式(Command Pattern) 15. 迭代器模式(Iterator Pattern) 16. 观察者模式(Observer Pattern) 17. ...

    用Java实现23种设计模式

    享元模式(Flyweight Pattern) 代理模式(Proxy Pattern) 3. 行为型模式 责任链模式(Chain of Responsibility Pattern) 命令模式(Command Pattern) 解释器模式(Interpreter Pattern) 迭代器模式...

    软件模式之Flyweight模式.docx

    《软件模式之Flyweight模式》 Flyweight模式是一种设计模式,其主要目的是通过共享技术来减少内存中对象的数量,从而优化内存使用效率。在对象数量庞大且大部分状态可以外部化的情况下,Flyweight模式尤其适用。它...

    23种设计模式 (创建型,结构型,行为型)

    享元模式(Flyweight Pattern) 12. 代理模式(Proxy Pattern) 13. 模板方法(Template Method) 14. 命令模式(Command Pattern) 15. 迭代器模式(Iterator Pattern) 行为型: 16. 观察者模式(Observer Pattern...

    C++ Flyweight模式

    Flyweight模式是一种设计模式,属于结构型模式的一种,它主要解决的是在大量对象创建时可能导致的内存消耗问题。在计算机科学中,尤其是编程领域,内存管理是一个关键的话题,Flyweight模式就是为了解决这个问题而...

    设计模式PPT

     享元模式(Flyweight Pattern)  代理模式(Proxy Pattern) 行为型模式用来对类或对象怎样交互和怎样分配职责进行描述,主要包含以下11种设计模式:  责任链模式(Chain of Responsibility Pattern)  ...

    设计模式学习笔记--Flyweight享元模式.docx

    享元模式的核心是Flyweight类,它是需要被共享的对象,通常包含两个部分:内在状态(Intrinsic State)和外在状态(Extrinsic State)。内在状态是指对象内部不变的部分,可以在多个对象之间共享;外在状态是随环境...

    常见设计模式的解读和对应代码示例,包括设计原则和软件工程中类之间的依赖关系

    1、基础概念 1.2 类间关系 关联关系(Association) 聚合关系(Aggregation) 组合关系(Composition) 依赖关系(Dependency) 泛化关系(Generalization) 实现关系(Realization) ...享元模式(Flyweight Pattern)

    C++设计模式课件13_Flyweight_享元模式.pdf

    享元模式(Flyweight Pattern)是设计模式中的一种优化模式,主要用于减少创建大量相似对象所需的内存消耗。在C++程序设计中,当系统中存在大量的相同或相似的对象时,使用享元模式可以有效地降低内存占用,提高系统...

Global site tag (gtag.js) - Google Analytics