享元模式可以帮助你运用共享技术有效的支持大量细粒度的对象。Flyweight是一个共享对象,它可以同时在多个场景中使用,并且在每个场景中flyweight都可以作为一个独立的对象——这点和非共享对象的实例没有区别。例如,在文本编辑器中,所有的字符都会在开始时初始化,并在全局内共享所有字符,而不是每个字符就创建对象。
Flyweight适用于有大量的对象,且这些对象可以分为外部状态和内部状态两个部分,这样就可以将内部状态分离开来,创建独立的共享对象。在使用Flyweight时,一般会使用一个FlyweightFactory来帮助用户创建和查找某个特定对象。
public interface Flyweight {
public String operation();
public void setLeft(Flyweight node);
public void setRight(Flyweight node);
public Flyweight getLeft();
public Flyweight getRight();
}
public class ConcreteFlyweight implements Flyweight{
private Flyweight intrinsicState = null;
private Flyweight left = null;
private Flyweight right = null;
public ConcreteFlyweight(String value){
intrinsicState = FlyweightFactory.getFlyweight(value);
}
@Override
public String operation() {
StringBuilder ss = new StringBuilder(intrinsicState.operation());
if(left != null) ss.append(left.operation());
if(right != null) ss.append(right.operation());
return ss.toString();
}
@Override
public void setLeft(Flyweight node) {
left = node;
}
@Override
public void setRight(Flyweight node) {
right = node;
}
@Override
public Flyweight getLeft() {
return left;
}
@Override
public Flyweight getRight() {
return right;
}
}
public class FlyweightFactory {
private static Map<String, Flyweight> pool = new HashMap<>();
public static Flyweight getFlyweight(String key){
if(pool.containsKey(key)){
return pool.get(key);
} else {
Flyweight fw = new internalFlyweight(key);
pool.put(key, fw);
return fw;
}
}
private static class internalFlyweight implements Flyweight{
private String value = null;
public internalFlyweight(String value){
this.value = value;
}
@Override
public String operation() {
return value;
}
@Override
public void setLeft(Flyweight node) {
throw new RuntimeException("unsupport!");
}
@Override
public void setRight(Flyweight node) {
throw new RuntimeException("unsupport!");
}
@Override
public Flyweight getLeft() {
throw new RuntimeException("unsupport!");
}
@Override
public Flyweight getRight() {
throw new RuntimeException("unsupport!");
}
}
}
public class Client {
@Test
public void test(){
Flyweight root = buildTree(new String[]{"a", "b", "c","a","b","c"});
System.out.println(root.operation());
}
//构建一棵节点树,这棵树按照广度优先,一层一层向下
public Flyweight buildTree(String strs[]){
return dfs(strs, 0);
}
private Flyweight dfs(String strs[], int index){
Flyweight root = new ConcreteFlyweight(null);
if(index < strs.length){
root = new ConcreteFlyweight(strs[index]);
}
if(2*index+1 < strs.length){
root.setLeft(dfs(strs, 2*index+1));
}
if(2*index+2 < strs.length){
root.setRight(dfs(strs, 2*index+2));
}
return root;
}
}
这里将字符作为Flyweight对象,FlyweightFactory内部包含了一个所有Flyweight对象的pool,当查找Flyweight对象时,如果存在pool中,则不再创建而是直接复用,而不存在时,则需要创建。这样字符的内容作为内部状态被共享,而字符间的关系作为外部状态被额外存储在节点信息中。通过Flyweight模式可以在需要大量字符时减少存储字符所需要的空间。