Flyweight(享元模式)
意图:运用共享技术有效地支持大量细粒度的对象。
结构图
在以下情况使用
- 一个应用程序使用了大量的对象
- 完全由于使用大量的对象造成很大的存储开销
- 对象的大多数状态都可以变为外部状态
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
- 应用程序不依赖对象标识。由于Flyweight对象可以被共享,因此对于概念上明显有别的对象,标识测试将返回真值。
实现
flyweight是一个共享对象,它可以同时在多个场景中使用,并且在每个场景中flyweight都可以作为一个独立的对象。
一般flyweight有外部状态和内部状态的区别。内部状态储存于flyweight,它包含了独立于场景的信息,这信息使得flyweight被共享,外部信息取决于场景,不可共享。
就像字符串一样,MyString由MyChar组成,一个MyString包含一个或多个MyChar,可以采用Flyweight技术,让所有的MyString共享MyChar,而不用对每个MyChar new操作。在这里,内部状态是MyChar自身的信息,外部状态是MyChar在MyString中的位置(list的索引).
MyChar
public class MyChar {
private char c;
public MyChar(char c) {
this.c = c;
}
@Override
public String toString() {
return String.valueOf(c);
}
}
MyString 通过构造方法传入的字符串进行解析,加入list
public class MyString {
private List<MyChar> list = new ArrayList<>();
private CharFactory charFactory = CharFactory.getInstance();
public MyString(String str) {
for (char c : str.toCharArray()) {
MyChar myChar = charFactory.getMyChar(c);
list.add(myChar);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (MyChar myChar : list) {
sb.append(myChar);
}
return sb.toString();
}
}
CharFactory 对MyString传的char在pool(hashmap)中查找,不存在就新建MyChar并加入pool返回,存在直接返回pool中MyChar的引用
public class CharFactory {
private Map<Character,MyChar> pool = new HashMap<>();
private static class Singleton{
private static final CharFactory charFactory = new CharFactory();
}
public static CharFactory getInstance(){
return Singleton.charFactory;
}
public MyChar getMyChar(char c){
MyChar myChar ;
if(pool.containsKey(c)){
System.out.println("pool存在:"+c);
myChar = pool.get(c);
}else {
System.out.println("pool不存在:"+c+",创建并加入pool");
myChar = new MyChar(c);
pool.put(c,myChar);
}
return myChar;
}
}
相关模式
Flyweight模式通常和Composite模式结合起来,用共享叶节点的有向无环图实现一个逻辑上的层次结构。
通常,最好用flyweight实现State和Strategy对象。