1.定义
享元模式是池技术的重要实现方式。使用共享对象可以有效的支持大量的细粒度的对象。
享元模式的定义提到了细粒度和共享对象,要求细粒度,那就很可能会产生大量相似对象,由此,在这里需要用到共享技术,来减少大量对象的产生,防止内存的大量消耗。这里引入来内部状态和外部状态两个概念。
内部状态
内部状态是对象可共享出来的信息,储存在对象内部并且不会随着环境的改变而发生改变。他可以作为一个对象的动态附加信息,不必直接存储在具体的某个对象中,属于可以共享的部分。
外部状态
外部状态是对象不可共享出来的信息,是随着环境改变而改变的。
在享元模式中可以共享的相同内容称为内部状态(IntrinsicState),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。
在享元模式中共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。
2.享元模式UML图
享元模式UML图
角色介绍
Flyweight 抽象享元角色,简单说就是一个产品的抽象类或者接口,同时定义出外部状态和内部状态的接口或者实现
ConcreteFlyweight 具体享元角色,具体的一个产品类,实现了抽象角色中定义的业务。需要注意的是内部状态的处理应该与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态,这是绝对不允许的
unsharedConcreteFlyweight 不可共享的享元角色,不存在外部状态或者安全要求(如线程安全)不能使用共享技术的对象。该对象一般不会出现在享元工厂。
FlyweightFactory 享元工厂,就是构造一个对象池,同时提供从池中获得对象的方法。
3.简单实现
3.1抽象享元角色
public interface Flyweight {
void operation(String extrinsic);
}
3.2具体享元角色
public class ConcreteFlyweight implements Flyweight {
private String intrinsicState;
public ConcreteFlyweight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String extrinsic) {
System.out.println("内部状态为"+intrinsicState);
System.out.println("外部状态为"+extrinsic);
System.out.println("本类为"+this);
}
}
3.3享元工厂
public class FlyweightFactory {
private static Map weights = new HashMap();
public static Flyweight factory(String state){
Flyweight flyweight = weights.get(state);
if(flyweight == null){
//如果对象不存在则创建一个新的Flyweight对象
flyweight = new ConcreteFlyweight(state);
//把这个新的Flyweight对象添加到池中
weights.put(state, flyweight);
}
return flyweight;
}
}
3.4客户端调用
public class MyClass {
public static void main(String args[]) {
Flyweight flyweight1= FlyweightFactory.factory("1");
flyweight1.operation("a");
Flyweight flyweight2=FlyweightFactory.factory("2");
flyweight2.operation("b");
Flyweight flyweight3=FlyweightFactory.factory("1");
flyweight3.operation("b");
}
}
打印结果
内部状态为1
外部状态为a
本类为com.example.lib1.shared.ConcreteFlyweight@1540e19d
内部状态为2
外部状态为b
本类为com.example.lib1.shared.ConcreteFlyweight@677327b6
内部状态为1
外部状态为b
本类为com.example.lib1.shared.ConcreteFlyweight@1540e19d
从例子中可以看出,最后客户端处是要新建三个对象,但是从打印结果可以看到,第一个和第三个对象实际为同一个,也就是只创建了两个。通过内部状态作为key值进行区别,外部状态根据环境要求做相应的修改。
4.总结
优点 享元模式的优点在于它大幅度地降低内存中相似对象的数量
缺点 提高了复杂性,为了使对象可以共享,将一些状态外部化
使用场景 系统中存在大量相似对象。需要缓冲池的场景。