享元模式
1、简介
享元模式是对象的结构模式,以共享的方式高效的支持大量的细粒度对象,也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。
享元对象做到共享的关键是区分内蕴状态和外蕴状态
1.1、内蕴状态:内蕴状态是存储在享元对象内部的,不会随环境改变而发生改变的。
1.2、外蕴状态:外蕴状态是不可以共享的状态,需要由客户端保存,并在享元对象创建后,在需要的时候再传入到享元对象的内部,外蕴状态不可以影响内蕴状态,他们是互相独立的
2、享元模式类图
3、从上面类图可以看出,享元模式涉及以下几个角色
3.1、抽象享元角色:此角色是所有具体享元类的超类,为这些类规定出需要实现的公共接口
3.2、具体享元角色:实现抽象享元角色所规定的接口,享元对象的内蕴状态必须与所处的环境无关,从而使得享元对象可以在整个系统中共享。
3.3、享元工厂角色:本角色负责创建和管理享元对象,本角色必须保证享元对象可以被系统合适的共享。
3.4、测试客户端 :本角色需要维护一个对所有享元对象的引用,还需要自己维护所有享元对象的外蕴状态
4、源代码
4.1、抽象享元角色
package FlyweightPattem; /** * ******************************************************** * @ClassName: Flyweight * @Description: 抽象享元角色 ********************************************************** */ public abstract class Flyweight { public abstract void operation(String state); }
4.2、具体享元角色
package FlyweightPattem; /** * ******************************************************** * @ClassName: ConcreteFlyweight * @Description: 具体享元角色 ********************************************************** */ public class ConcreteFlyweight extends Flyweight{ private Character intrinsicState = null; //构造器 将内蕴状态当作参数传入 public ConcreteFlyweight(Character state) { this.intrinsicState = state; } /** * ********************************************************** * @Title: operation * @Description: 外蕴状态作为参数传入方法中,改变方法的行为 * 但是并不改变对象的内蕴状态 * @param @param states 设定文件 * @return void 返回类型 * @throws ********************************************************** */ @Override public void operation(String state) { System.out.println("\nintrinsicState = " +intrinsicState+ " state = "+state); } }
4.3、享元工厂角色
package FlyweightPattem; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; /** * ******************************************************** * @ClassName: FlyweightFactory * @Description:享元工厂 ********************************************************** */ public class FlyweightFactory { //这个map在这里 作为一个对象常量池来使用 @SuppressWarnings("rawtypes") private HashMap files = new HashMap(); private Flyweight inkFlyweight; public Flyweight factory(Character state){ if(files.containsKey(state)){ return (Flyweight) files.get(state); }else{ Flyweight fly = new ConcreteFlyweight(state); files.put(state, fly); return fly; } } //检查打印的方法 public void checkFlyweight(){ Flyweight flyweight; int i= 0; System.out.println("\n==========checkFlyweight()============"); for(Iterator it = files.entrySet().iterator();it.hasNext();){ Map.Entry e = (Map.Entry) it.next(); System.out.println("item"+(++i)+":"+e.getKey()); } System.out.println("==========checkFlyweight()============"); } }
4.4、测试客户端
package FlyweightPattem; /** * ******************************************************** * @ClassName: FlyweightTest * @Description: 享元模式测试客户端 ********************************************************** */ public class FlyweightTest { public static void main(String[] args) { //创建享元工厂对象 FlyweightFactory factory = new FlyweightFactory(); //调用工厂对象生成一个内蕴对象为a的享元对象 Flyweight fly = factory.factory('a'); //传入外蕴状态 fly.operation("Frist Call"); //调用工厂对象生成一个内蕴对象为b的享元对象 fly = factory.factory('b'); //传入外蕴状态 fly.operation("second Call"); //调用工厂对象生成一个内蕴对象为a的享元对象 fly = factory.factory('a'); //传入外蕴状态 fly.operation("Third Call"); //调用checkFlyweight方法 打印出所有独立的享元对象 factory.checkFlyweight(); } }
5、测试,运行结果如下
6、总结
使用享元模式需要维护一个记录系统已有享元对象的表,这需要额外的消耗资源,所以,应当在有足够多的享元实例可以共享的时候才使用这个模式
可以看出,享元模式的优点在于可以大幅度降低内存中对象的数量,但是,相应的付出的代价也很高,
享元模式是系统变得更复杂,为了使对象可以共享,需要将一些状态外部化,从而使得逻辑变得非常复杂
其次,外部化的状态,读取外部状态也需要消耗额外的资源。