美文网首页
<<设计模式之禅(第二版)>>——第二十

<<设计模式之禅(第二版)>>——第二十

作者: leiiiooo | 来源:发表于2016-10-23 13:06 被阅读15次
    定义:
    • 使用共享对象可有效地支持大量的细粒度的对象。

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

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

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

    享元模式的通用类图
    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<String, Flyweight> 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对客户端来说是完全相同的,主要解决复用,而享元模式主要解决的是对象的共享问题,如何建立多个可共享的细粒度对象则是其关注的重点。

    相关文章

      网友评论

          本文标题:<<设计模式之禅(第二版)>>——第二十

          本文链接:https://www.haomeiwen.com/subject/rlxkuttx.html