享元模式的目的是复用。复用那些细粒度的小对象,从而减少系统中对象的数量,提高系统性能。
模式的关键:
1. 分清内蕴状态(可共享,对象一旦创建就不能改变)和外蕴状态(不可共享,又外部环境负责维护)
2. FlyweightFactory工厂的存在把获取享元对象的过程封装起来。该工厂一般设计为单例模式。
分为单纯享元模式和复合享元模式。
一、单纯享元模式
1.1 不带外蕴状态的享元模式
import java.util.HashMap; import java.util.Map; // 不带外蕴状态的单纯享元模式 public class Test5 { public static void main(String[] args) { FlyweightFactory factory = FlyweightFactory.getInstance(); Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf1.show(); Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B); cf2.show(); Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf1.show(); } } // 抽象享元 abstract class Flyweight { public abstract void show (); } // 具体享元类 class ConcreteFlyweight extends Flyweight { private char value; // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。 public ConcreteFlyweight(char internalState) { this.value = internalState; } @Override public void show() { System.out.println("字母:" + this.value); } } class FlyweightFactory { // singleton private static final FlyweightFactory instance = new FlyweightFactory(); private Map<String, Flyweight> cache = new HashMap<String, Flyweight>(); public static final String KEY_CHAR_A = "A"; public static final String KEY_CHAR_B = "B"; private FlyweightFactory () {} public static FlyweightFactory getInstance() { return instance; } public Flyweight getFlyweight(String key) { if (cache.get(key) != null) { return cache.get(key); } if (key.equals(KEY_CHAR_A)) { cache.put(KEY_CHAR_A, new ConcreteFlyweight('A')); return cache.get(key); } else if (key.equals(KEY_CHAR_B)) { cache.put(KEY_CHAR_B, new ConcreteFlyweight('B')); return cache.get(key); } return null; } }
字母:A
字母:B
字母:A
1.2. 带外蕴状态的享元模式
import java.util.HashMap; import java.util.Map; // 带外蕴状态的单纯享元模式 public class Test5 { public static void main(String[] args) { FlyweightFactory factory = FlyweightFactory.getInstance(); Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf1.show(" 字体:宋体"); // 外部状态由客户端维护 Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B); cf2.show(" 大小:12px"); Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf3.show(" 字体:隶书"); } } // 抽象享元 abstract class Flyweight { public abstract void show (String externState); // 业务方法 } // 具体享元类 class ConcreteFlyweight extends Flyweight { private char value; // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。 public ConcreteFlyweight(char internalState) { this.value = internalState; } // 外部状态通过参数传给享元对象,从而改变享元对象的行为,但是对享元对象的内部状态没有任何影响 @Override public void show(String externState) { System.out.println("字母:" + this.value + "; 外部状态【" + externState + "】"); } } class FlyweightFactory { // singleton private static final FlyweightFactory instance = new FlyweightFactory(); private Map<String, Flyweight> cache = new HashMap<String, Flyweight>(); public static final String KEY_CHAR_A = "A"; public static final String KEY_CHAR_B = "B"; private FlyweightFactory () {} public static FlyweightFactory getInstance() { return instance; } public Flyweight getFlyweight(String key) { if (cache.get(key) != null) { return cache.get(key); } if (key.equals(KEY_CHAR_A)) { cache.put(key, new ConcreteFlyweight('A')); return cache.get(key); } else if (key.equals(KEY_CHAR_B)) { cache.put(key, new ConcreteFlyweight('B')); return cache.get(key); } return null; } }运行结果:(请求3次,只生成两个享元对象,但是因为外蕴状态的加入,2个享元对象表现出3种不同的行为) 字母:A; 外部状态【 字体:宋体】
字母:A; 外部状态【 字体:隶书】
1.3 复合享元模式
import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; // 复合享元模式 public class Test5 { public static void main(String[] args) { FlyweightFactory factory = FlyweightFactory.getInstance(); // 获取单纯享元 Flyweight cf1 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf1.show(" 字体:宋体"); // 外部状态由客户端维护 Flyweight cf2 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_B); cf2.show(" 大小:12px"); Flyweight cf3 = factory.getFlyweight(FlyweightFactory.KEY_CHAR_A); cf3.show(" 字体:隶书"); // 获取复合享元 Flyweight composit = factory.getFlyweight(Arrays.asList(new String[]{"A","B","B","B","A"})); composit.show("粗体、黑色"); } } // 抽象享元 abstract class Flyweight { public abstract void show (String externState); // 业务方法 } // 具体享元类 class ConcreteFlyweight extends Flyweight { private char value; // 内蕴状态,对象创建后,内蕴状态就不再改变。因此,具体享员类一般设计为不变类。 public ConcreteFlyweight(char internalState) { this.value = internalState; } // 外部状态通过参数传给享元对象,从而改变享元对象的行为,但是对享元对象的内部状态没有任何影响 @Override public void show(String externState) { System.out.println("字母:" + this.value + "; 外部状态【" + externState + "】"); } } //复合享元类。 //之所以引入复合享元,是为了把那些外蕴状态相同的单纯享元集中起来进行管理。 class CompositeFlyweight extends Flyweight { // 持有单纯享元的集合。这些单纯享元的外蕴状态和当前复合享元的外蕴状态相同。 private Map<String, Flyweight> map = new HashMap<String, Flyweight>(); public CompositeFlyweight(){} public void add(String key, Flyweight flyweight) { map.put(key, flyweight); } public void show(String externState) { Set<String> set = map.keySet(); for (String key : set) { map.get(key).show(externState); // 每个具体的享元的外蕴状态和当前复合享元的外蕴状态相同 } } } // 分别提供获取单纯享元和复合享元的方法 class FlyweightFactory { // singleton private static final FlyweightFactory instance = new FlyweightFactory(); private Map<String, Flyweight> cache = new HashMap<String, Flyweight>(); public static final String KEY_CHAR_A = "A"; public static final String KEY_CHAR_B = "B"; private FlyweightFactory () {} public static FlyweightFactory getInstance() { return instance; } // 获取单纯享元对象 public Flyweight getFlyweight(String key) { if (cache.get(key) != null) { return cache.get(key); } if (key.equals(KEY_CHAR_A)) { cache.put(key, new ConcreteFlyweight('A')); return cache.get(key); } else if (key.equals(KEY_CHAR_B)) { cache.put(key, new ConcreteFlyweight('B')); return cache.get(key); } return null; } // 获取复合享元对象 public Flyweight getFlyweight(List<String> keys) { CompositeFlyweight composit = new CompositeFlyweight(); for (String key : keys) { composit.add(key, this.getFlyweight(key)); // 复合享元中的单纯享元还是通过获取单纯享元的方法中得到 } return composit; } }
// 单纯享元
字母:A; 外部状态【 字体:宋体】
字母:B; 外部状态【 大小:12px】
字母:A; 外部状态【 字体:隶书】
// 复合享元
字母:A; 外部状态【粗体、黑色】
字母:B; 外部状态【粗体、黑色】