享员模式
概述:
所谓享员模式就是运用共享技术有效地支持大量细粒度对象的复用,Java语言中String类型就使用了享元模式。String对象是不变对象,一旦创建出来就不能改变。在jvm内部,String对象是共享的,如果一个系统有两个String对象所包含字符串相同的话,jvm实际只创建一个string对象提供给两个引用,从而实现string对象的共享。
共享模式支持大量细粒度对象的复用。
内部状态:在享元对象内部不随外部环境改变而变化的共享部分。
外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。
抽象享元角色:具体享元类的超类,那些需要外蕴状态的操作可以调用商业方法以参数形式传入。
具体享元角色:实现抽象享元角色所规定的接口,如果有内蕴状态的话,必须负责为内蕴状态提供存储空间,享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
3.享元工厂角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象,如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
4.客户端角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。
abstract class FlyWeight{ public abstract void operation(); } class ConcrateFlyWeight extends FlyWeight { String str; public ConcrateFlyWeight(String str) { super(); this.str = str; } @Override public void operation() { // TODO Auto-generated method stub System.out.println("concrate fly " + str); } } package Flyweight; import java.util.Hashtable; public class FlyweightFactory{ private Hashtable flyweights = new Hashtable();//----------------------------1 public FlyweightFactory(){} public Flyweight getFlyWeight(Object obj){ Flyweight flyweight = (Flyweight) flyweights.get(obj);//----------------2 if(flyweight == null){//---------------------------------------------------3 //产生新的ConcreteFlyweight flyweight = new ConcreteFlyweight((String)obj); flyweights.put(obj, flyweight);//--------------------------------------5 } return flyweight;//---------------------------------------------------------6 } public int getFlyweightSize(){ return flyweights.size(); } }
享元模式应当在什么条件下使用?
当以下所有条件都满足时,可以考虑使用享元模式
1.一个系统有大量的对象
2.这些对象的耗费大量的内存
3.这些对象的状态中的大部分都可以外部化
4.这些对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象替代
5.软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
最后,使用享元模式需要维护一个记录了系统已有的所有享元对象的表,而这需要耗费资源,因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。
优缺点:
1.享元模式使得系统更加复杂,为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化
2.享元模式将享元对象的状态外部化,而读取外部状态使得运行时间稍微变长