设计模式系列:搞懂享元模式,用对象池缓存相同对象

享元模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。通过对象的共享减少创建对象的数量、降低内存消耗,从而提高系统资源的利用率。属于结构型模式。

享元模式提出了两个要求,细粒度和共享对象。我们把对象的状态分为两个部分:内部状态和外部状态。内部状态指对象共享出来的信息,存储在享元信息内部,并且是不变的,外部状态变化的。享元模式的本质就是缓存共享对象,降低内存消耗。

享元模式的结构:享元模式的主要角色有3个。

  1. 抽象享元角色(Flyweight):定义了具体享元类需要实现的公共接口,可以是接口或抽象类。
  2. 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
  3. 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
  4. 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户端请求一个享元对象时,享元工厂检査是否已存在该享元对象,如果存在直接返回该对象,如果不存在就创建享元对象并返回。

享元模式的通用实现:

//抽象享元角色
public interface Flyweight {
    void operation(String outState);
}

//具体享元角色
public class ConcreteFlyweight implements Flyweight {
    private String key;

    public ConcreteFlyweight(String key){
        this.key = key;
        System.out.println("具体享元对象" + key + "被创建!");
    }

    @Override
    public void operation(String outState) {
        System.out.print("具体享元对象" + key + "被调用,");
        System.out.println("外部状态是:" + outState);
    }
}

//享元工厂
public class FlyweightFactory {
    private ConcurrentHashMap<String, Flyweight> flyweightMap = new ConcurrentHashMap<String, Flyweight>();

    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = flyweightMap.get(key);
        if (flyweight == null) {
            flyweight = new ConcreteFlyweight(key);
            flyweightMap.put(key,flyweight);
        } else {
            System.out.println("具体享元" + key + "已经存在,被成功获取!");
        }
        return flyweight;
    }
}

//测试类
public class FlyweightTest {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight flyweightA1 = factory.getFlyweight("a");
        Flyweight flyweightA2 = factory.getFlyweight("a");
        Flyweight flyweightA3 = factory.getFlyweight("a");
        flyweightA1.operation("第1次调用a");
        flyweightA2.operation("第2次调用a");
        flyweightA3.operation("第3次调用a");
    }
}

享元模式的结构图:

享元模式的应用实例:租房买房时一般都需要中介带看房源,不同中介之间房源是可以共享的,因此房源就是内部状态,是不会改变的,而带看的中介是外部状态,每次带看可能不是同一个中介。我们就来模拟一下中介带看房源的场景。

//房源接口
public interface IHouse {
    void showMsg(String anency);
}

//具体房源类
public class House implements IHouse{
    private String address;

    public House(String address){
        this.address = address;
        System.out.println("创建房源:"+address);
    }

    @Override
    public void showMsg(String anency) {
        System.out.println("中介"+anency+"带看房源:"+address);
    }
}

//房源工厂
public class HouseFactory {
    private static ConcurrentHashMap<String,IHouse> houseMap = new ConcurrentHashMap<>();

    public static IHouse getHouseMag(String address){
        if(houseMap.containsKey(address)){
            System.out.println("缓存查看:"+address);
            return houseMap.get(address);
        }
        System.out.println("首次查看,创建房源!");
        IHouse house = new House(address);
        houseMap.put(address,house);
        return house;
    }
}

//测试类
public class HouseTest {
    public static void main(String[] args) {
        IHouse house1 = HouseFactory.getHouseMag("北京天安门");
        house1.showMsg("张三");
        IHouse house2 = HouseFactory.getHouseMag("北京天安门");
        house2.showMsg("李四");
        IHouse house3 = HouseFactory.getHouseMag("北京天安门");
        house3.showMsg("王五");
    }
}

享元模式的优点:减少对象的创建,降低内存中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。

享元模式的缺点:

  1. 关注对象内、外部状态,关注线程安全。
  2. 增加程序的逻辑复杂性。

享元模式的使用场景:享元模式是通过减少内存中对象的数量来节省内存空间的,所以以下几种情形适合采用享元模式。

  1. 系统中存在大量相同或相似的对象,这些对象耗费大量的内存资源。
  2. 大部分的对象可以按照内部状态进行分组,且可将不同部分外部化,这样每一个组只需保存一个内部状态。
  3. 由于享元模式需要额外维护一个保存享元的数据结构,所以应当在有足够多的享元实例时才值得使用享元模式。

享元模式在源码中的应用:

  1. String字符串常量池。
  2. 当Integer类型的值在-128~127之间时,对象直接从IntegerCache中取。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风雨编码路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值