亨元(Flyweight Pattern)模式
1、亨元模式的用意
亨元模式是对象的结构模式。亨元模式以共享的方式高效地支持大量的细粒度对象。
亨元模式能做到共享的关键是区分内蕴状态和外蕴状态
一个内蕴状态是存储在亨元对象内部的,并且是不会随环境改变而有所不同的。因此,一个亨元可以具有内蕴状态并可以共享。
一个外蕴状态是随环境改变而改变的、不可以共享的状态。亨元对象的外蕴状态必须由客户端保存,并在亨元对象被创建之后,
在需要使用的时候再传入到亨元对象内部。
外蕴状态不可以影响亨元对象的内蕴状态的,它们是相互独立的。
2、亨元模式的种类
根据所涉及的亨元对象的北部表象,亨元模式可以分为单纯亨元模式和复合亨元模式两种形式。
3、亨元模式的实现:
1)单纯亨元模式涉及的角色
1-抽象亨元角色:此角色是所有的具体亨元类的超类,为这些规定出需要实现的公共接口,那些需要外蕴状态的操作
可以通过方法的参数传入。抽象亨元的接口使得亨元变得可能,但是并不强制子类实行共享,因此并非所有的亨元
对象都是可以共享的
2-具体亨元角色:实现抽象亨元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
亨元对象的内蕴状态必须与对象所处的周围环境无关,从而使得亨元对象可以在系统内共享。有时候具体亨元角色
又叫做单纯具体亨元角色,因为复合亨元角色是由单纯具体亨元角色通过复合而成的
3-复合亨元角色:复合亨元角色所代表的对象是不可以共享的,但是一个复合亨元对象可以分解成为多个本身是单纯亨元
对象的组合。复合亨元角色又称做不可共享的亨元对象。
4-亨元工厂角色:本角色负责创建和管理亨元角色。本角色必须保证亨元对象可以被系统适当地共享。
当一个客户端对象请求一个亨元对象的时候,亨元工厂角色需要检查系统中是否已经有一个符合要求的亨元对象,
如果已经有了,亨元工厂角色就应当提供这个已有的亨元对象;如果系统中没有一个适当的亨元对象的话,
亨元工厂角色就应当创建一个新的合适的亨元对象。
5-客户端角色:本角色还需要自行存储所有亨元对象的外蕴状态。
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()==============");
}
}