享元模式
享元模式:是一种重要的池技术的实现方式,使用共享对象可有效地支持大量的细粒度的对象。
享元模式的定义提出了两个要求:细粒度的对象和共享对象,分配太多的对象到应用程序当中去将有损程序的性能,而且还容易造成内存溢出,通过享元模式的共享对象的技术来解决这些问题。首先我们先了解一下对象的内部状态(intrinsic)和外部状态(extrinsic)。
内部状态:对象可共享出来的信息,存储在享元对象的内部并且不会随环境改变而改变,作为一个对象的动态附加信息,不必直接存储在具体某个对象中。
外部状态:对象得以依赖的一个标记,随环境的改变而改变、不可共享的状态,是一批对象的统一标识,是唯一的一个索引值。
有了对象的两种状态,我们来看一下享元模式的通用类图:
public abstract class Flyweight {
//内部状态
private String intrinsic;
//外部状态
protected final String extrinsic;
public Flyweight(String extrinsic){
this.extrinsic = extrinsic;
}
public abstract void operate();
public String getIntrinsic(){
return this.intrinsic;
}
public void setIntrinsic(String intrinsic){
this.intrinsic = intrinsic;
}}
public class ConcreteFlyweight1 extends Flyweight{
public ConcreteFlyweight1(String extrinsic) {
super(extrinsic);
// TODO Auto-generated constructor stub
}
@Override
public void operate() {
// TODO Auto-generated method stub
}}
public class FlyweightFactory {
private static HashMap<String, Flyweight> flyWeights = new HashMap<String, Flyweight>();
public static Flyweight getFlyweight(String key){
Flyweight flyweight = null;
if(flyWeights.containsKey(key)){
flyweight = flyWeights.get(key);
}else{
//根据外部状态创建享元对象
flyweight = new ConcreteFlyweight1(key);
//将享元对象放到池中
flyWeights.put(key, flyweight);
}
return flyweight;
}}
View Code
享元模式的优缺点
享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但同时也提高了系统的复杂性,需要分离出外部状态和内部状态,而外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统逻辑混乱。
享元模式的使用场景
系统中存在大量的相似对象;
细粒度的对象具备较近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
需要缓冲池的场景。
享元模式的扩展
线程安全问题,当多个线程同时从对象缓冲池中取对象,并对对象的内部状态进行修改时,可能会造成线程的不安全。
public class MultiThread extends Thread{
private Flyweight flyweight;
private String intrinsic;
public MultiThread(Flyweight flyweight){
this.flyweight = flyweight;
this.intrinsic = flyweight.getIntrinsic();
}
public void run(){
String intrinsic = flyweight.getIntrinsic();
if(!intrinsic.equalsIgnoreCase(this.intrinsic)){
System.out.print("线程不安全......");
System.out.println(this.intrinsic + " " + intrinsic);
}
}}
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Flyweight flyweight = FlyweightFactory.getFlyweight("123");
while(true){
flyweight.setIntrinsic("intrinsic1");
new MultiThread(flyweight).start();
flyweight.setIntrinsic("intrinsic2");
new MultiThread(flyweight).start();
}
}}
View Code
性能问题,尽量使用Java基本类型作为外部状态(即为key),如果自定义对象作为外部状态会降低系统执行的效率。

Comments | NOTHING