享元模式
享元模式(Flyweight Pattern),Flyweight在拳击比赛中是最轻量级别--“蝇量级"。享元模式以共享的方式支持大量的细粒度对象。
享元模式在编辑系统中被大量使用,例如字母a会在许多的地方出现,尽管所出现的位置和字模风格不尽相同,但是都可以共享一个字母a的对象。
Java中的String是final的,改变String的内容就是一个新的String了。只要是内容相同,多个String对象是可以共享一个String实例的。
享元模式可以分为单纯享元模式和复合享元模式两种。
单纯享元模式中,所有享元对象都是可以共享的。下面是单纯享元模式的类图:
核心是FlyweightFactory,采取的是登记的工厂方式,用HashMap存储已经构造的ConcreteFlyweight。调用时先去查看HashMap是否已经存在,已存在则直接调用。不存在时先创建再添加到HashMap中以共享使用。
Flyweight接口的示例代码:
public abstract class Flyweight{ public abstract void operation(String state); }
具体类ConcreteFlyweight的示例代码:
public class ConcreteFlyweight extends Flyweight{ private Character intrinsicState = null; public ConcreteFlyweight(Character state){ this.intrinsicState = state; } public void operation(String state){ System.out.print( " Intrinsic State = " + intrinsicState + ", Extrinsic State = " + state); } }
工厂类FlyweightFactory的示例代码:
public class FlyweightFactory{ private HashMap flies = new HashMap(); private Flyweight lnkFlyweight; public FlyweightFactory(){ } 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(" ==========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("==========checkFlyweight()============="); } }
客户端client的示例代码:
public class Client{ private static FlyweightFactory factory; public static void main(String[] args){ factory = new FlyweightFactory(); Flyweight fly = factory.factory(new Character('a')); fly.operation("First Call"); fly = factory.factory(new Character('b')); fly.operation("Second Call"); fly = factory.factory(new Character('a')); fly.operation("Third Call"); // intrinsic Flyweight factory.checkFlyweight(); } }
客户端client在创建2个对象”a”时实际上是共享了一个对象。
复合享元模式的类图如下所示:
共享的不再是单纯的对象,而是由合成模式合成的复杂对象。类图中的Flyweight,ConcreteFlyweight和ConcreteCompositeFlyweight就构成了合成模式。ConcreteCompositeFlyweight中可以包含ConcreteFlyweight,从而合成更为复杂的对象。
和单纯享元模式相比较,变化较大是FlyweightFactory和ConcreteCompositeFlyweight。
下面是FlyweightFactory的实例代码。 加入了一个factory(String compositeState) ,compositeState的每个字符被作为一个ConcreteFlyweight加入到ConcreteCompositeFlyweight中。实际应用中compositeState应该是Vector<Object>。
public class FlyweightFactory{ private HashMap flies = new HashMap(); private Flyweight lnkFlyweight; public FlyweightFactory(){} 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)){ 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(" ==========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(" ==========checkFlyweight()============="); } }
ConcreteCompositeFlyweight的示例代码为:
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); } } }
一个咖啡摊的例子,咖啡摊虽然每天卖出的咖啡数量很多,但是咖啡的种类是固定且有限的,这里享元模式就很适用。类图如下:
单纯享元模式就很合适,Order充当了抽象接口,Flavor是具体的实现,FlavorFactory采用的是登记的工厂模式。
订单的代码:
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("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 Client{ private static Order[] flavors = new Flavor[100]; 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"); takeOrders("Black Coffee"); takeOrders("Espresso"); for (int i = 0; i < ordersMade; i++){ flavors[i].serve(); } System.out.println(" Total teaFlavor objects made: " + flavorFactory.getTotalFlavorsMade()); } }
从flavorFactory.getTotalFlavorsMade()的结果可以看出,工厂类中登记的咖啡种类只哟3种。