设计模式之享元模式

享元模式(FlyWeight),其含义是运用共享技术有效地支持大量细粒度的对象,即系统只使用少量的对象,而这些对象都相近,状态变化很小,对象使用次数却很多。

享元模式能做到共享的关键是区分内蕴状态和外蕴状态,一个内蕴状态是存储在享元对象内部的,并且是不会随环境改变而有所不同的。因此一个享元可以具有内蕴状态并可以共享。一个外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态不可以影响享元对象的内蕴对象。换句话说,它们是互相独立的。

其适用性:

一个应用程序使用了大量的对象,

完全由于使用大量的对象,造成很大的存储开销,

对象的大多数状态都可变为外部状态,

如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,

应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

  结构如下:

          设计模式之享元模式 

  享元模式在使用时分为单纯享元模式和复合享元模式两种,单纯享元模式中Flyweight都是可共享的,也是现在Flyweight实现的较多实例。现在先列出单纯享元模式:

 Flyweight.java

package org.designpattern.structural.flyweight;

    public abstract class Flyweight {
         protected Character intrinsicState;

         protected Flyweight(Character intrinsicState){
             this.intrinsicState = intrinsicState;
         };
         public abstract  void  operation(String extrinsicState);
         public Character getIntrinsicState(){
             return this.intrinsicState;
         };
     }

  ConcreteFlyweight.java继承了Flyweight,实现了一个operation方法,类略。Flyweight是通过工厂得到的,下面是FlyweightFactory.java

package org.designpattern.structural.flyweight;
import java.util.HashMap;

public class FlyweightFactory {
    private HashMap flyWeights;
       public FlyweightFactory(){
         flyWeights = new HashMap();
    }
    public Flyweight getFlyweight(Character key){
         if(this.flyWeights.containsKey(key)){
            System.out.println(key + " already created!");
            return (Flyweight) flyWeights.get(key);
        }else{
             Flyweight flyweight = new ConcreteFlyweight(key);
             flyWeights.put(key,flyweight);
             return flyweight;
        }
    }

  如果是单纯享元模式,到这里再加上客户测试类就结束了。如果使用复合享元模式,复合元素的对象的状态是会改变的,所以复合享元对象是不能共享的。需要再增加一个类UnsharedConcreteFlyeweight.java

public class UnsharedConcreteFlyweight extends Flyweight {

    private HashMap<Character,Flyweight> unsharedFlyweights;
    private Flyweight  flyweight;

    public UnsharedConcreteFlyweight(Character intrinsicState) {
        super(intrinsicState);
        this.unsharedFlyweights = new HashMap(20);
    }

    public void add(Character key,Flyweight flyweight){
        this.unsharedFlyweights.put(key,flyweight);
    }
    @Override
    public void operation(String extrinsicState) {
        System.out.println("extrinsicState:" + extrinsicState);
        Iterator<Map.Entry<Character,Flyweight>> it = unsharedFlyweights.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<Character,Flyweight> entry = it.next();
            Flyweight fly = entry.getValue();
            fly.operation(extrinsicState);
        }
    }

   } 

此时在FlyweighFactory.java中需要增加一个方法支持不可共享的Flyweight的调用:

 public Flyweight getUnsharedFlyweight(String keys ){

        UnsharedConcreteFlyweight unsharedConcreteFlyweight = new UnsharedConcreteFlyweight(null);
        for(int i=0;i<keys.length();i++){
            Character character = new Character(keys.charAt(i));
            unsharedConcreteFlyweight.add(character,getFlyweight(character));
        }
        return unsharedConcreteFlyweight;

    }

 下面是客户测试类:

   package org.designpattern.structural.flyweight;
   public class Main {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fly1 = factory.getFlyweight('a');
        fly1.operation("First call!");
        Flyweight fly2 = factory.getFlyweight('b');
        fly2.operation("Second call!");
        Flyweight fly3 = factory.getFlyweight('a');
        fly3.operation("Third call!");
        System.out.println(fly1 == fly3);

        Flyweight unsharedFlyweight = factory.getUnsharedFlyweight("abcde");
        unsharedFlyweight.operation("Forth call!");
     }

  } 

 享元模式的有效性很大程度上取决于在何种情景下使用它,其主要缺点是使系统设计变得更加复杂,将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。我们通常会把Flyweight工厂设计为单例模式,其可以和许多模式共同使用更有效。