享元模式

享元模式

       以共享的方式高效的支持大量的细粒度对象。享元对象以内蕴和外蕴状态达到对象共享。

      

1.1内蕴状态  

       存储在享元对象内部,不会随环境的改变而改变。因为其不可变,所以内蕴状态是可以共享的。内蕴状态在对象创建后就不会改变。

1.2外蕴状态

       会随着环境的改变而改变,不可共享。由客户端保存外蕴状态,在需要使用的时候传入享元对象内部。

2.1单纯享元模式

2.1.1结构:

  • 抽象享元角色:

  所有具体享元类的超类。规定出公共接口。需要外蕴状态的操作可以通过参数形式传入。

  • 具体享元角色(ConcreteFlyweight):

  实现抽象享元角色规定的接口。如果有内蕴状态,必须负责为内蕴状态低筒存储空间,且与对象所处的周围环境无关。

  • 享元工厂角色(FlyweightFactory):

  负责创建和管理享元角色。必须保证享元对象可以被系统适当的共享。客户端调用一个享元对象时,享元工厂角色会检查系统是否已有符合要求的享元角色。有则返回,无则创建。

  • 客户端角色(Client):

  维护所有享元对象的引用。自行存储所有享元对象的外蕴状态。

 

2.1.2代码

抽象享元角色:

/**
 * 抽象享元角色
 */
public interface Flyweight {
    void operate(String outerState);
}

 

具体享元角色: 

/**
 * 具体享元角色
 */
public class ConcreteFlyweight implements Flyweight{
    private String innerState = null;

    /**
     * 通过构造器初始化内蕴状态
     * 由于客户端不能直接初始化具体享元对象,所以这里的构造器可以设为私有的,
     *    然后通过一个初始化方法进行内蕴状态的初始化
     */
    public ConcreteFlyweight(String innerState) {
        this.innerState = innerState;
    }

    @Override
    public void operate(String outerState) {
        System.out.println("外蕴状态:" + outerState + ";内蕴状态:" + innerState);
    }
}

 

享元工厂: 

/**
 * 享元工厂角色
 */
public class FlyweightFactory {
    private Map<String, Flyweight> files = new HashMap<>();

    public FlyweightFactory() {
    }

    public Flyweight factory(String innerState){
        if(files.containsKey(innerState)){
            return files.get(innerState);
        }else{
            Flyweight flyweight = new ConcreteFlyweight(innerState);
            files.put(innerState, flyweight);
            return flyweight;
        }
    }

    public void printAll(){
        System.out.println(new Gson().toJson(files));
    }
}


客户端: 

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight = factory.factory("内蕴状态1");
        flyweight.operate("外蕴状态1");

        flyweight = factory.factory("内蕴状态2");
        flyweight.operate("外蕴状态2");

        flyweight = factory.factory("内蕴状态1");
        flyweight.operate("外蕴状态3");

        factory.printAll();
    }
}

 

2.2复合享元模式 

2.2.1结构:

  • 抽象享元角色:

  所有具体享元类的超类。规定出公共接口。需要外蕴状态的操作可以通过参数形式传入。

  • 具体享元角色(ConcreteFlyweight):

  实现抽象享元角色规定的接口。如果有内蕴状态,必须负责为内蕴状态低筒存储空间,且与对象所处的周围环境无关。

  • 复合享元角色(UnsharableFlyweight)

  不可共享。可以分解为多个单纯享元角色组合。

  • 享元工厂角色(FlyweightFactory):

  负责创建和管理享元角色。必须保证享元对象可以被系统适当的共享。客户端调用一个享元对象时,享元工厂角色会检查系统是否已有符合要求的享元角色。有则返回,无则创建。

  • 客户端角色(Client):

  维护所有享元对象的引用。自行存储所有享元对象的外蕴状态。

 

 

2.2.2代码:

抽象享元角色:

/**
 * 抽象享元角色
 */
public interface Flyweight {
    void operate(String outerState);
}

 

具体享元角色: 

/**
 * 具体享元角色
 */
public class ConcreteFlyweight implements Flyweight {
    private String innerState = null;

    /**
     * 通过构造器初始化内蕴状态
     * 由于客户端不能直接初始化具体享元对象,所以这里的构造器可以设为私有的,
     *    然后通过一个初始化方法进行内蕴状态的初始化
     */
    public ConcreteFlyweight(String innerState) {
        this.innerState = innerState;
    }

    @Override
    public void operate(String outerState) {
        System.out.println("外蕴状态:" + outerState + ";内蕴状态:" + innerState);
    }
}

 

复合享元角色: 

/**
 * 复合享元角色
 */
public class CompositeFlyweight implements Flyweight {
    private Map<String, Flyweight> files = new HashMap<>();

    private Flyweight flyweight;
    @Override
    public void operate(String outerState) {
        Iterator it = files.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry e = (Map.Entry) it.next();
            flyweight = (Flyweight) e.getValue();
            flyweight.operate(outerState);
        }
    }

    public void add(String key, Flyweight flyweight){
        files.put(key, flyweight);
    }
}


享元工厂角色: 

/**
 * 享元工厂角色
 */
public class FlyweightFactory {
    private Map<String, Flyweight> files = new HashMap<>();

    public FlyweightFactory() {
    }

    public Flyweight factory(List<String> compositeState){
        CompositeFlyweight compositeFlyweight = new CompositeFlyweight();
        for(String state : compositeState){
            System.out.println("facotry("+ state +")");
            compositeFlyweight.add(state, this.factory(state));
        }
        return compositeFlyweight;
    }
    public Flyweight factory(String innerState){
        if(files.containsKey(innerState)){
            return files.get(innerState);
        }else{
            Flyweight flyweight = new ConcreteFlyweight(innerState);
            files.put(innerState, flyweight);
            return flyweight;
        }
    }

    public void printAll(){
        System.out.println(new Gson().toJson(files));
    }
}


客户端: 

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweight = factory.factory("内蕴状态1");
        flyweight.operate("外蕴状态1");

        flyweight = factory.factory("内蕴状态2");
        flyweight.operate("外蕴状态2");

        flyweight = factory.factory("内蕴状态1");
        flyweight.operate("外蕴状态3");

        List<String> state = Arrays.asList("内蕴状态1","内蕴状态2","内蕴状态3");
        factory.factory(state);

        factory.printAll();
    }
}


3小结
 

       对象可以按内蕴状态分组,即一个内蕴状态代表一个对象。享元工厂维护了所有享元对象。通过内蕴状态去获取一个唯一的享元对象出来。享元对象都必须由享元工厂获取。享元模式大幅度降低内存中的对象数量。但却加大了系统的复杂性。在一些特定环境下,享元模式是个大杀器。如文本编辑器,五子棋。

 

 

 

 

 

参考:

《Java与模式》

posted @ 2018-12-16 11:47  Simple°  阅读(233)  评论(0编辑  收藏  举报