<<设计模式之禅(第二版)>>——第二十八章 享元模式

定义:
  • 使用共享对象可有效地支持大量的细粒度的对象。

将对象信息划分为: 内部状态(intrinsic)、外部状态(extrinsic)

内部状态:内部状态是对象可以共享出来的信息,存储在享元对象内部并且不会随环境改变而改变,它们可以作为一个对象的动态附加信息,不必直接存储在某个具体对象中,属于可以共享的部分。

外部状态:是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态,他是一批对象的统一标识,是唯一的一个索引值。

<<设计模式之禅(第二版)>>——第二十八章 享元模式_第1张图片
享元模式的通用类图
public abstract class Flyweight {
  private String intrinsic;

  public String getIntrinsic() {
    return intrinsic;
  }

  public void setIntrinsic(String intrinsic) {
    this.intrinsic = intrinsic;
  }

  protected final String extrinsic;// final

  // 享元角色接受外部的状态
  public Flyweight(String _extrinsic) {
    // TODO Auto-generated constructor stub
    this.extrinsic = _extrinsic;
  }

  // 定义业务操作
  public abstract void operate();

}


public class ConcreteFlyweightOne extends Flyweight {

  public ConcreteFlyweightOne(String _extrinsic) {
    super(_extrinsic);
    // TODO Auto-generated constructor stub
  }

  @Override
  public void operate() {
    // TODO Auto-generated method stub

  }

}

public class ConcreteFlyweightTwo extends Flyweight {

  public ConcreteFlyweightTwo(String _extrinsic) {
    super(_extrinsic);
    // TODO Auto-generated constructor stub
  }

  @Override
  public void operate() {
    // TODO Auto-generated method stub

  }

}

/*
 * 创建享元对象工厂
 * */
public class FlyweightFactory {
  // 定义对象池
  private static HashMap pool = new HashMap<>();

  // 享元工厂
  public static Flyweight getFlyweight(String extrinsic) {
    Flyweight flyweight = null;
    if (pool.containsKey(extrinsic)) {
        flyweight = pool.get(extrinsic);
    } else {
        // 创建享元对象,并放入pool中
        flyweight = new ConcreteFlyweightOne(extrinsic);
        pool.put(extrinsic, flyweight);
    }
    return flyweight;
  }
}
优点和缺点:
  • 大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能,但同时也提高了系统的复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统的逻辑混乱。
使用场景:
  • 系统存在大量的相似对象
  • 细粒度的对象都具备接近的外部状态,而且内部状态与环境无关,对象没有特定身份
  • 需要缓冲池的场景
享元模式拓展
  • 线程安全的问题:我们在使用享元模式的时候,对象池中的享元对象尽量多,多到足够满足业务为止
  • 性能平衡:尽量使用java基本类型作为外部状态(如果把一个对象作为Map类的键值,一定要确保重写了equals和hashCode方法,否则会出现搜索失败的情况)
最佳实践:
public class Test {// api 中的享元模式
  public static void main(String[] args) {
    String str1 = "和谐";
    String str2 = "社会";
    String str3 = "和谐社会";
    String str4;
    str4 = str1 + str2;
    System.out.println(str4 == str3);
    str4 = (str1 + str2).intern();
    System.out.println(str4 == str3);
  }
}

>false
>true

虽然可以使用享元模式来实现对象池,但是二者还是有比较大的区别,对象池着重在对象的复用上,对象池中的每个对象都是可替换的,从对象池中取出的对象a、对象b对客户端来说是完全相同的,主要解决复用,而享元模式主要解决的是对象的共享问题,如何建立多个可共享的细粒度对象则是其关注的重点。

你可能感兴趣的:(<<设计模式之禅(第二版)>>——第二十八章 享元模式)