享元模式
享元模式
以共享的方式高效的支持大量的细粒度对象。享元对象以内蕴和外蕴状态达到对象共享。
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与模式》