设计模式之享元模式

享元模式

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 让你能在有限的内存容量中载入更多对象。其本质就是缓存共享对象,降低内存消耗

享元模式将需要重复使用的对象分为两个部分:内部状态和外部状态。

​ 内部状态是不会变化的,可以被多个对象共享,而外部状态会随着对象的使用而改变。比如,连接池中的连接对象,保存在连接对象中的用户名、密码、连接URL等信息,在创建对象的时候就设置好了,不会随环境的改变而改变,这些为内部状态。而当每个连接要被回收利用时,我们需要将它标记为可用状态,这些为外部状态

应用场景

仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式

应用该模式所获的收益大小取决于使用它的方式和情景。 它在下列情况中最有效:

  1. 程序需要生成数量巨大的相似对象,这将耗尽目标设备的所有内存
  2. 对象中包含可抽取且能在多个对象间共享的重复状态。

例如:

  1. 当程序中需要创建大量的相似对象时,可以使用享元模式来共享相同的内部状态,减少对象的重复创建,节省内存开销
  2. 当系统运行效率较低,存在大量的内存开销时,可以采用享元模式来优化内存使用,加快程序的执行速度
  3. 当系统中的对象访问比较频繁时,可以使用享元模式来优化系统性能,减少重复对象的创建和销毁,提高程序的运行效率
  4. 当系统中需要共享一些公共对象或静态数据时,可以使用享元模式来降低系统的开销,提升系统的性能。
  5. 当系统需要考虑加强安全控制时,可以使用享元模式来保证对对象访问的控制,实现权限控制、缓存控制等功能。

从上述不难看出,享元模式适用于需要创建大量相似的对象以及共享公共信息的场景,同时也适用于需要考虑性能优化共享控制的系统。但是使用之前一定要考虑清楚,还是那句话,不要为了使用设计模式而去使用设计模式。

实现方式

  1. 将需要改写为享元的类成员变量拆分为两个部分:
    • 内在状态: 包含不变的、 可在许多对象中重复使用的数据的成员变量。
    • 外在状态: 包含每个对象各自不同的情景数据的成员变量
  2. 保留类中表示内在状态的成员变量, 并将其属性设置为不可修改。 这些变量仅可在构造函数中获得初始数值。
  3. 找到所有使用外在状态成员变量的方法, 为在方法中所用的每个成员变量新建一个参数, 并使用该参数代替成员变量。
  4. 你可以有选择地创建工厂类来管理享元缓存池, 它负责在新建享元时检查已有的享元。 如果选择使用工厂, 客户端就只能通过工厂来请求享元, 它们需要将享元的内在状态作为参数传递给工厂。
  5. 客户端必须存储和计算外在状态 (情景) 的数值, 因为只有这样才能调用享元对象的方法。 为了使用方便, 外在状态和引用享元的成员变量可以移动到单独的情景类中。

代码示例

public abstract  class Car {
    protected  String color;
    protected  double price;

    public Car(String color, int price){
        this.color=color;
        this.price=price;
    }

    //展示汽车信息
    public abstract void show();
}

public class BaoMa extends Car {
    public BaoMa(String color, int price) {
        super(color, price);
    }

    @Override
    public void show() {
        System.out.println("生产成功:宝马 颜色="+color+","+"起售价="+price+"元");
    }
}

public class BYD extends Car {
    public BYD(String color, int price) {
        super(color, price);
    }

    @Override
    public void show() {
        System.out.println("生产成功:比亚迪 颜色="+color+","+" 起售价="+price+"元");
    }
}

public class CarFactory {
    public static Map<String, Car> carMap = new HashMap<>();

    public static Car getCar(String color, String type,Double price){
        String key=color+"_"+type;
        if(carMap.containsKey(key)){
            //如果已经有该颜色和类型的汽车,直接返回
            System.out.println("已经有相同汽车,直接从carMap中获取 ");
            return carMap.get(key);
        }else {
            Car car =null;
            //没有,创建并放入缓存
            if("BYD".equals(type)){
                car =new BYD(color,10000);
            }else if ("BaoMa".equals(type)){
                car =new BaoMa(color,2000);
            }else {
                System.out.println("抛异常!没有该类型的汽车");
            }
            //放入缓存
            carMap.put(key, car);
            return car;
        }
    }
}

优缺点

优点

​ 如果程序中有很多相似对象, 那么你将可以节省大量内存。

缺点

  1. 你可能需要牺牲执行速度来换取内存, 因为他人每次调用享元方法时都需要重新计算部分情景数据。
  2. 代码会变得更加复杂。程序员必须时刻根据系统的实际情况以及内部状态和外部状态的不同选择使用对象池或享元工厂来管理内存和共享对象,进一步增加了系统的复杂度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大伟攀高峰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值