享元模式的目的是复用。复用那些细粒度的小对象,从而减少系统中对象的数量,提高系统性能。
模式的关键:
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;
}
}
// 运行结果: (请求了3次,但是只生成了2个对象)
字母: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; 外部状态【 字体:宋体】字母:B; 外部状态【 大小:12px】
字母: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; 外部状态【粗体、黑色】