zl程序教程

您现在的位置是:首页 >  后端

当前栏目

2022-10-10-享元模式

模式 2022 10 享元
2023-06-13 09:13:58 时间

解释器模式第一遍没有读懂,看到后面说实际项目中很少用到,因为它会引起效率、性能以及维护等问题,会直接用已有的成熟的工具。

又看了一遍有点明白了,有点类似写算法题遇到的情况,又有点编译原理里面的味道。不过既然用不到,像我这种三流的程序员也就不想深究了。

想想技术书永远别买纸书,技术更新太快,有些书买来很快就过期了,没用了,卖二手都卖不出去,再看也没太大价值,只能当废纸,成本太高。这《设计模式之禅》虽然没有技术过期的问题,但买了纸书,现在还是在看电子版的,在公司也不适合看纸书,而且属于看完记录完也不想再看的书。

以后凡是不需要阅读多遍的书,都不要花钱去买纸书。

享元模式

池中共享对象,减少对象创建,减小 OOM 机率。

比如 Android 从 xml 构建 View 时的构造器。Map 保存对象,有就拿出来用,没有再创建存到 Map 中去。

将对象的信息分成内部状态和外部状态两类,内部状态可以没有。外部状态就是需要调用者传进来的参数,来控制生成一个什么样的对象。通过这个状态判断池子里是否有可以直接复用的。

// 抽象的享元类
public abstract class Flyweight { 
    //内部状态
    private String intrinsic; 
    //外部状态,final 不许子类修改
    protected final String Extrinsic; 
    
    //要求享元角色必须接受外部状态。
    public Flyweight(String _Extrinsic){ 
        this.Extrinsic = _Extrinsic;
    }  
    //定义业务操作  
    public abstract void operate();
     
    //内部状态的getter/setter  
}

// 具体的享元类
public class ConcreteFlyweight extends Flyweight{ 
    //接受外部状态
    public ConcreteFlyweight2(String _Extrinsic){ 
        super(_Extrinsic);
    } 
    //根据外部状态进行逻辑处理 
    public void operate(){
        //业务逻辑
    } 
}

// 享元工厂
public class FlyweightFactory { 
    //定义一个池容器
    private static HashMap<String,Flyweight> pool= new HashMap<String,Flyweight 
    
    //享元工厂,参数传入外部状态
    public static Flyweight getFlyweight(String Extrinsic){
        Flyweight flyweight = null; 
        if(pool.containsKey(Extrinsic)){
            flyweight = pool.get(Extrinsic);
        }else{
            flyweight = new ConcreteFlyweight(Extrinsic);  
            pool.put(Extrinsic, flyweight);
        }  
        return flyweight;
    }
}

// 场景类
public class Client {
    public void test() {
        Flyweight weight = FlyweightFactory.getFlyWeight("ex-abc"); // 构建了一个对象
        weight.setIntrinsic("in-abc"); // 设置它自己的内部状态
        // 然后这个对象用完了,不需要了。又有一个内部状态是 “in-bcd"的了
        Flyweight weight = FlyweightFactory.getFlyWeight("ex-abc");
        weight.setIntrinsic("in-bcd"); 
        // 如果用普通的 new 对象,内存里是同时有两个对象
        // 但现在其实是一个对象,只不过修改了内部状态值
    }
}

应用场景:

  • 系统中存在大量的相似对象。
  • 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。
  • 需要缓冲池的场景。

虽然可以使用享元模式可以实现对象池,但是这两者还是有比较大的差异,对象池着重在对象的复用上,池中的每个对象是可替换的,从同一个池中获得 A对象和 B 对象对客户端来说是完全相同的,它主要解决复用,而享元模式在主要解决的对象的共享问题,如何建立多个可共享的细粒度对象则是其关注的重点。