设计模式——享元模式
享元模式就是通过使用共享的方式,达到高效地支持大量的细粒度对象。它的目的就是节省占用的空间资源,从而实现系统性能的改善。
享元对象的所有状态分成两类:
享元对象的第一类状态称为内蕴状态(Internal State)。它不会随环境改变而改变,存储在享元对象内部,因此内蕴状态是可以共享的,对于任何一个享元对象来讲,它的值是完全相同的。
享元对象的第二类状态称为外蕴状态(External State)。它会随环境的改变而改变,因此是不可以共享的状态,对于不同的享元对象来讲,它的值可能是不同的。享元对象的外蕴状态必须由客户端保存,在享元对象被创建之后,需要使用的时候再传入到享元对象内部。
实现要素:
抽象享元类(Flyweight):它是所有具体享元类的超类。为这些类规定出需要实现的公共接口,那些需要外蕴状态的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
具体享元类(ConcreteFlyweight):具体享元类实现了抽象享元类所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元类又称为单纯具体享元类,因为复合享元类是由单纯具体享元角色通过复合而成的。
具体复合享元类(ConcreteCompositeFlyweight):复合享元类,又叫做不能共享的享元类。一个复合享元对象是由多个单享元对象组成,这些组成的对象是可以共享的,但是复合享元类本身并不能共享。
享元工厂类(FlyweightFactoiy):享元工厂类负责创建和管理享元对象。当一个客户端对象请求一个享元对象的时候,享元工厂需要检查系统中是否已经有一个符合要求的享元对象,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
适用性:
1、一个系统中存在着大量的细粒度对象;
2、这些细粒度对象耗费了大量的内存。
3、这些细粒度对象的状态中的大部分都可以外部化;
4、这些细粒度对象可以按照内蕴状态分成很多的组,当把外蕴对象从对象中剔除时,每一个组都可以仅用一个对象代替。
5、软件系统不依赖于这些对象的身份,换言之,这些对象可以是不可分辨的。
优点
在于它大幅度地降低内存中对象的数量。
缺点
1、享元模式为了使对象可以共享,它需要将部分状态外部化,这使得系统的逻辑变得复杂。
2、享元模式将享元对象的部分状态外部化,而读取外部状态使得运行时间会有所加长。
总结
满足以上的这些条件的系统可以使用享元对象。最后,使用享元模式需要维护一个记录了系统已有的所有享元的哈希表,也称之为对象池,而这也需要耗费一定的资源。因此,应当在有足够多的享元实例可供共享时才值得使用享元模式。如果只能够节省百八十个对象的话,还是没有必要引入享元模式的,毕竟性价比不高。
实现
在网上看到的例子几乎都是举的是关于字母的那个例子。这里就接着造人以后造工具来进行实现。类图如下:
ITool(享元接口)定义:
package com.lidaming.design13.flyweight; /** * 享元接口 * @author admin * */ public interface ITool { void produce(String ext); }
ConcreteTool具体工具类(单纯享元类)实现:
package com.lidaming.design13.flyweight; public class ConcreteTool implements ITool { private String name; public ConcreteTool(String intenal) { this.name = intenal; } public void produce(String ext) { System.out.println("flyweight intenal:" + this.name); System.out.println("flyweight ext:" + ext); } }
ConcreteCompositeTool复合工具类(复合享元类)实现:
package com.lidaming.design13.flyweight; import java.util.HashMap; public class ConcreteCompositeTool implements ITool { HashMap<String, ITool> tools = new HashMap<String, ITool>(); public void add(String key, ITool tool) { tools.put(key, tool); } public void produce(String ext) { ITool tool = null; for (String item : tools.keySet()) { tool = tools.get(item); tool.produce(ext); } } }
ToolFactory工具工厂类实现:
package com.lidaming.design13.flyweight; import java.util.HashMap; import java.util.List; public class ToolFactory { HashMap<String, ITool> tools = new HashMap<String, ITool>(); /** * 组合享元类 * * @param compositeNames * @return */ public ITool factory(List<String> compositeNames) { ConcreteCompositeTool compositeTool = new ConcreteCompositeTool(); for (String item : compositeNames) { compositeTool.add(item, factory(item)); } return compositeTool; } /** * 单纯享元方法 * * @param intenal * @return */ public ITool factory(String intenal) { ITool tool = tools.get(intenal); if (tool == null) { tool = new ConcreteTool(intenal); tools.put(intenal, tool); } return tool; } }
场景类实现:
package com.lidaming.design13.flyweight; import java.util.ArrayList; import java.util.List; public class Client { public static void main(String[] args) { List<String> compositeNames = new ArrayList<String>(); compositeNames.add("a"); compositeNames.add("b"); compositeNames.add("c"); compositeNames.add("d"); ToolFactory toolFactory = new ToolFactory(); ITool compositeTool2 = toolFactory.factory(compositeNames); ITool compositeTool1 = toolFactory.factory(compositeNames); compositeTool1.produce("ddd"); ITool tool1 = toolFactory.factory("e"); ITool tool2 = toolFactory.factory("e"); System.out.println("-----------------"); System.out.println("组合享元类能否共享:" + (compositeTool1 == compositeTool2)); System.out.println("单纯享元类能否共享:" + (tool1 == tool2)); } }
参考
http://blog.csdn.net/wanghao72214/article/details/4046182
http://www.cnblogs.com/java-my-life/archive/2012/04/26/2468499.html