享元模式是对象的结构模式,它以共享的方式高效地支持大量的细粒度对象。
享元对象能做到共享的关键是区分内蕴状态和外蕴状态。
一个内蕴状态是存储在享元对象内部的,并且是不会随环境改变而改变的,因此一个享元可以具有内蕴状态并可以共享。
一个外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由由端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。
外蕴状态不可以影响享元对象的内蕴状态。换句话说,它们是相互独立的。
享元模式在编辑器系统中大量使用。一个文编辑器往往会提供很多种字体,而通常的做法就是将每一个字母做成一个享元对象。享元对象的内蕴状态就是这个字母,而字母在文本中的位置和字体风格等其他信息则是外蕴状态。比如,字母a可以出现在文本的很多地方,虽然这些字母a的位置和字体风格不同,但是所有这些地方使用的都是同一个字母对象。这样一来,字母对象就可以在整个系统中共享。
享元模式的优点在于它大幅度地降低内存中对象的数量,但是,它做到这一点所付出的代价也是很高的:
享元模式使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
享元模式将享元享元对象的状态外部化,而读取外部状态使得运行时间稍微变长。
享元模式可以分为单纯享元模式和复杂享元模式,后者可以认为是前者是组合。
以下是示例代码:
package flyweight.simple;
public interface Flyweight ... {
public void func();
}
package flyweight.simple;
public class ConcreteFlyweight implements Flyweight ... {
private String data = null;
public ConcreteFlyweight (String data) ...{
this.data = data;
}
public void func() ...{
System.out.println(this + ".func() : " + data);
}
}
package flyweight.simple;
import java.util. * ;
public class FlyweightFactory ... {
private HashMap flies = new HashMap();
Flyweight factory (String data) ...{
if (flies.containsKey(data)) ...{
return (Flyweight)flies.get(data);
}else ...{
Flyweight fly = new ConcreteFlyweight(data);
flies.put(data,fly);
return fly;
}
}
public void checkFlyweight () ...{
int i=0;
System.out.println(this + ".checkFlyweight()");
for (Iterator it = flies.entrySet().iterator();it.hasNext();) ...{
Map.Entry e = (Map.Entry)it.next();
System.out.println("item " + (++i) + " : " + e.getKey());
}
}
}
package flyweight.simple;
public class Client ... {
public static void main(String[] args) ...{
Flyweight flyweight1, flyweight2, flyweight3;
FlyweightFactory ff = new FlyweightFactory();
flyweight1 = ff.factory("aaa");
flyweight2 = ff.factory("bbb");
flyweight3 = ff.factory("aaa");
flyweight1.func();
flyweight2.func();
flyweight3.func();
ff.checkFlyweight();
}
}
package flyweight.composite;
public interface Flyweight ... {
public void func();
}
package flyweight.composite;
public class ConcreteFlyweight implements Flyweight ... {
private String data = null;
public ConcreteFlyweight (String data) ...{
this.data = data;
}
public void func() ...{
System.out.println(this + ".func() : " + data);
}
}
package flyweight.composite;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class CompositeConcreteFlyweight implements Flyweight ... {
private HashMap flies = new HashMap(10);
public void add (String data, Flyweight fw) ...{
flies.put(data,fw);
}
public void func() ...{
for (Iterator it = flies.entrySet().iterator();it.hasNext();) ...{
Map.Entry e = (Map.Entry)it.next();
Flyweight fw = (Flyweight)e.getValue();
fw.func();
}
}
}
package flyweight.composite;
import java.util. * ;
public class FlyweightFactory ... {
private HashMap flies = new HashMap();
CompositeConcreteFlyweight factory (String data) ...{
int len = data.length();
CompositeConcreteFlyweight ccfw = new CompositeConcreteFlyweight();
for (int i=0;i<len;i++) ...{
ccfw.add(String.valueOf(data.charAt(i)),this.innerFactory(String.valueOf(data.charAt(i))));
}
return ccfw;
}
private Flyweight innerFactory (String data) ...{
if (flies.containsKey(data)) ...{
return (Flyweight)flies.get(data);
}else ...{
Flyweight fly = new ConcreteFlyweight(data);
flies.put(data,fly);
return fly;
}
}
public void checkFlyweight () ...{
int i=0;
System.out.println(this + ".checkFlyweight()");
for (Iterator it = flies.entrySet().iterator();it.hasNext();) ...{
Map.Entry e = (Map.Entry)it.next();
System.out.println("item " + (++i) + " : " + e.getKey());
}
}
}
package flyweight.composite;
public class Client ... {
public static void main(String[] args) ...{
FlyweightFactory ff = new FlyweightFactory();
Flyweight ccfw = ff.factory("ubuntu");
ccfw.func();
ff.checkFlyweight();
}
}