享元模式
享元模式 |
- 享元模式:是一种重要的池技术的实现方式,使用共享对象可有效地支持大量的细粒度的对象。
- 享元模式的定义提出了两个要求:细粒度的对象和共享对象,分配太多的对象到应用程序当中去将有损程序的性能,而且还容易造成内存溢出,通过享元模式的共享对象的技术来解决这些问题。首先我们先了解一下对象的内部状态(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; } }
享元模式的优缺点 |
享元模式是一个非常简单的模式,它可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但同时也提高了系统的复杂性,需要分离出外部状态和内部状态,而外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统逻辑混乱。
享元模式的使用场景 |
- 系统中存在大量的相似对象;
- 细粒度的对象具备较近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;
- 需要缓冲池的场景。
享元模式的扩展 |
- 线程安全问题,当多个线程同时从对象缓冲池中取对象,并对对象的内部状态进行修改时,可能会造成线程的不安全。
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(); } } }
- 性能问题,尽量使用Java基本类型作为外部状态(即为key),如果自定义对象作为外部状态会降低系统执行的效率。