设计模式 - 享元模式(Flyweight)

定义

运用共享技术有效的支持大量细粒度对象。

适用性

以下情况适用享元(Flyweight)模式:

  1. 一个应用程序使用了大量对象;
  2. 完全由于使用了大量的对象,造成很大的存储开销;
  3. 对象的大多数状态都可变为外部状态;
  4. 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象;
  5. 应用程序不依赖于对象标识。由于code>Flyweight</code>对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

结构

享元模式结构

参与者

抽象享元角色(Flyweight): 享元接口,通过这个接口Flyweight可以接受并作用于外部状态;

具体享元角色(ConcreteFlyweight): 实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight必须是可共享的,它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。

复合享元角色(UnsharableFlyweight): 非共享的享元实现对象,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象;

享元工厂角色(FlyweightFactoiy): 主要用来创建并管理共享的享元对象;并且确保合理的共享Flyweight,当用户请求一个Flyweight时,FlyweightFactoiy对象提供一个已创建的实例或者创建一个(如果不存在的话)。

客户端(Client): 维持一个对Flyweight的引用,计算或存储一个(或多个)Flyweight的外部状态。

优缺点

优点

(1)可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。

(2)外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

缺点

(1)使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。

(2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

享元模式实现

抽象享元(Flyweight)

public interface Flyweight {
    void operation(String state);
}

具体享元(ConcreteFlyweight)

public class ConcreteFlyweight implements Flyweight {
    private Character intrinsicState;

    public ConcreteFlyweight(Character state) {
        this.intrinsicState = state;
    }

    @Override
    public void operation(String state) {
        System.out.println("Intrinsic State = " + this.intrinsicState);
        System.out.println("Extrinsic State = " + state);
    }
}

复合享元(UnsharableFlyweight)

public class ConcreteCompositeFlyweight implements Flyweight {
    private Map<Character, Flyweight> files = new HashMap<>();

    public void add(Character key, Flyweight fly) {
        files.put(key, fly);
    }

    @Override
    public void operation(String state) {
        Flyweight fly;
        for (Object o : files.keySet()) {
            fly = files.get(o);
            fly.operation(state);
        }

    }
}

享元工厂(FlyweightFactoiy)

public class FlyweightFactory {
    private Map<Character, Flyweight> files = new HashMap<Character, Flyweight>();

    public Flyweight factory(List<Character> compositeState) {
        ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();

        for (Character state : compositeState) {
            compositeFly.add(state, this.factory(state));
        }

        return compositeFly;
    }

    public Flyweight factory(Character state) {
        Flyweight fly = files.get(state);
        if (fly == null) {
            fly = new ConcreteFlyweight(state);
            files.put(state, fly);
        }
        return fly;
    }

}

客户端(Client)

public class Client {
    public static void main(String[] args) {
        new Client().test();
    }

    void test() {
        List<Character> compositeState = new ArrayList<>(5);
        compositeState.add('a');
        compositeState.add('b');
        compositeState.add('c');
        compositeState.add('a');
        compositeState.add('b');

        FlyweightFactory flyFactory = new FlyweightFactory();
        Flyweight compositeFly1 = flyFactory.factory(compositeState);
        Flyweight compositeFly2 = flyFactory.factory(compositeState);
        compositeFly1.operation("Composite Call");

        Character state = 'a';
        Flyweight fly1 = flyFactory.factory(state);
        Flyweight fly2 = flyFactory.factory(state);

        System.out.println("compositeFly1 == compositeFly1:" + (compositeFly1 == compositeFly2));
        System.out.println("fly1 == fly2:" + (fly1 == fly2));
    }
}

参考代码

https://github.com/xueyufish/design-pattern-java/tree/master/flyweight