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("
intrinsicState = "
+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("
==========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、总结
使用享元模式需要维护一个记录系统已有享元对象的表,这需要额外的消耗资源,所以,应当在有足够多的享元实例可以共享的时候才使用这个模式
可以看出,享元模式的优点在于可以大幅度降低内存中对象的数量,但是,相应的付出的代价也很高,
享元模式是系统变得更复杂,为了使对象可以共享,需要将一些状态外部化,从而使得逻辑变得非常复杂
其次,外部化的状态,读取外部状态也需要消耗额外的资源。