当前位置: 首页 > article >正文

【设计模式-结构型】享元模式

一、什么是享元模式

       享元模式确实是一种结构型设计模式,其名称“享元”虽然听起来有些抽象,但其实包含了该模式的核心概念。我们可以将“享元”这个名字拆开来理解,以便更好地把握其含义和用途。

享元模式的命名解释

  1. “享”共享:享元模式的核心在于共享已存在的对象,而不是每次都创建新的对象。通过这种方式,多个客户端可以共享同一个对象实例,而不是每个客户端都拥有自己的独立实例。这种共享机制显著减少了内存的使用,提高了系统的性能和资源利用率。

  2. “元”基本元素或单元:享元模式将对象分解为基本的、可共享的单元。这些单元(享元对象)是构成更复杂对象的“元”素。通过共享这些基本单元,可以在多个地方复用它们,从而减少内存中对象的数量。

二、为什么用享元模式

  • 减少内存消耗:享元模式通过共享已存在的对象,减少了内存中对象的数量。这对于需要创建大量相似对象的场景特别有用,可以显著降低内存占用,提高系统的资源利用率。
  • 管理大量相似对象:当系统中存在大量相似或相同的对象时,享元模式可以有效地管理这些对象,避免重复创建。
  • 简化对象管理:享元工厂提供了一个集中的点来管理对象的创建和复用,使得对象的管理更加简单和高效。客户端代码不需要关心对象的创建细节,只需要通过工厂获取对象即可。
  • 优化资源使用:享元模式通过共享对象,优化了资源的使用。这对于资源受限的系统(如嵌入式系统或移动端应用)特别有用,可以确保系统在有限的资源下高效运行。

三、享元模式示例

3.1 用一个生活场景表述享元模式

        是不是很抽象,什么内部状态,什么共享,什么不能共享,听的有点晕乎乎。他和缓存或者内存中开发常用的map存储有啥区别,不都一样吗?这个差别可以留到下面解答。这个环节主要通过举一个例子来说明享元对应生活中的例子,并解释清楚享元的角色。

        享元我的理解,其实和近几年一个商业模式 特别的像。 就是我们常说的 “共享模式“,我相信多数人都接触过,比如 共享单车,共享汽车,共享充电宝等等。没错,他们就是用了享元模式。借阅人其实就是客户端,他会拿app去骑车,你会告诉公司 我需要一辆车,公司为了省钱肯定会告诉你附近哪里有一辆电动车,那么这个电动车就是内部状态,也就是可以共享的。也就是享元对象,那么谁借,谁骑行,骑到哪里,还车。 车的定位,借阅历史信息就是 外部状态。 当借的人多了一看,咋回事附近没车啊,这个时候 享元工厂 也就是公司 ,就会紧急生产享元对象(单车)进行投放。那么我们下面对应到享元对象的角色

3.2 享元模式角色定义

1. 抽象享元(Flyweight):定义了享元对象的接口,通过这个接口享元可以接受并作用于外部状态。在共享单车的例子中,这可以看作是共享单车的基本接口,定义了共享单车的基本操作,如解锁、骑行、归还等。

// 享元接口:共享单车
interface SharedBike {
    void use(String userId, String location, LocalDate borrowDate, LocalDate returnDate);
}

2. 具体享元(ConcreteFlyweight):实现抽象享元接口,为内部状态提供存储空间。具体享元对象必须是可共享的,它所存储的状态必须是内部状态,即独立于具体享元对象的场景。在共享单车的例子中,具体享元对象可以看作是每一辆具体的共享单车,其内部状态包括车型、颜色、配置等,这些属性在共享单车的生命周期内不会改变,并且可以被多个用户共享。

// 具体享元类:具体共享单车
class ConcreteSharedBike implements SharedBike {
    private String model;
    private String color;
    private String configuration;

    public ConcreteSharedBike(String model, String color, String configuration) {
        this.model = model;
        this.color = color;
        this.configuration = configuration;
    }

    @Override
    public void use(String userId, String location, LocalDate borrowDate, LocalDate returnDate) {
        System.out.println("车型: " + model);
        System.out.println("颜色: " + color);
        System.out.println("配置: " + configuration);
        System.out.println("借阅者: " + userId);
        System.out.println("位置: " + location);
        System.out.println("借阅日期: " + borrowDate);
        System.out.println("归还日期: " + returnDate);
    }
}

3. 享元工厂(FlyweightFactory):创建并管理享元对象,确保享元对象可以被正确地共享和复用。享元工厂维护一个对象池,存储已经创建的享元对象,以便复用。在共享单车的例子中,享元工厂可以看作是共享单车的运营公司,负责管理和调度共享单车,确保用户可以方便地获取和归还单车。

// 享元工厂:共享单车工厂
class SharedBikeFactory {
    private Map<String, SharedBike> bikes = new HashMap<>();

    public SharedBike getBike(String model, String color, String configuration) {
        String key = model + color + configuration;
        if (!bikes.containsKey(key)) {
            bikes.put(key, new ConcreteSharedBike(model, color, configuration));
        }
        return bikes.get(key);
    }
}

4.客户端(Client):使用享元对象的代码,通过享元工厂来请求所需的享元对象。客户端不直接创建享元对象,而是通过享元工厂来获取。在共享单车的例子中,客户端可以看作是用户,用户通过手机应用请求一辆共享单车,而不是自己去创建一辆新的单车。

// 客户端代码
public class FlyweightPatternDemo {
    public static void main(String[] args) {
        SharedBikeFactory factory = new SharedBikeFactory();

        // 用户1借阅一辆共享单车
        SharedBike bike1 = factory.getBike("共享单车A", "蓝色", "标准配置");
        bike1.use("用户1", "停车场A", LocalDate.now(), LocalDate.now().plusDays(1));

        // 用户2借阅一辆共享单车
        SharedBike bike2 = factory.getBike("共享单车A", "蓝色", "标准配置");
        bike2.use("用户2", "停车场B", LocalDate.now(), LocalDate.now().plusDays(1));

        // 用户3借阅一辆不同配置的共享单车
        SharedBike bike3 = factory.getBike("共享单车B", "黄色", "高级配置");
        bike3.use("用户3", "停车场C", LocalDate.now(), LocalDate.now().plusDays(1));

        // 检查是否共享
        System.out.println("bike1 和 bike2 是否相同: " + (bike1 == bike2));
    }
}




车型: 共享单车A
颜色: 蓝色
配置: 标准配置
借阅者: 用户1
位置: 停车场A
借阅日期: 2024-01-15
归还日期: 2024-01-16
车型: 共享单车A
颜色: 蓝色
配置: 标准配置
借阅者: 用户2
位置: 停车场B
借阅日期: 2024-01-15
归还日期: 2024-01-16
车型: 共享单车B
颜色: 黄色
配置: 高级配置
借阅者: 用户3
位置: 停车场C
借阅日期: 2024-01-15
归还日期: 2024-01-16
bike1 和 bike2 是否相同: true

内部状态和外部状态

  • 内部状态(Intrinsic State):指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变。在共享单车的例子中,内部状态包括车型、颜色、配置等,这些属性在共享单车的生命周期内不会改变,并且可以被多个用户共享。

  • 外部状态(Extrinsic State):指对象得以依赖的一个标记,是随环境改变而改变的,不可共享的状态。在共享单车的例子中,外部状态包括用户的借阅记录、当前位置、借阅时间、归还时间等,这些属性是特定于每次借阅的,每次借阅时都会有所不同。

3.3 享元模式和开发中类似的Map有啥区别

       其实炸一看是不是很像map,不就是缓存吗,你给我搞啥享元。其实他还是有区别的。

  1. 目的不同

    • 享元模式

      • 目的:通过共享已存在的对象来减少内存的使用,提高系统的性能和资源利用率。

      • 应用场景:适用于需要创建大量相似对象的场景,通过共享对象来减少内存占用。

    • 缓存(Map)

      • 目的:提高数据访问速度,减少对数据库或文件系统的访问次数,避免数据击穿。

      • 应用场景:适用于需要频繁访问、计算成本高昂的数据,通过缓存来提高系统的性能。例如,数据库查询结果缓存、API响应缓存等。

  2. 状态管理不同

    • 享元模式

      • 内部状态(Intrinsic State):对象的固有属性,这些属性在对象的生命周期内不会改变,并且可以被多个客户端共享。

      • 外部状态(Extrinsic State):对象的上下文相关属性,这些属性在不同的使用场景中可能会改变,并且不能被共享。

    • 缓存(Map)

      • 内部状态:缓存中存储的数据通常是不变的,只包含对象的内部状态。例如,缓存中的数据库查询结果、配置信息等。

      • 外部状态:缓存本身不涉及外部状态的管理,外部状态通常由客户端或其他组件管理。

  3. 实现方式不同

    • 享元模式

      • 享元工厂(FlyweightFactory):负责管理和共享享元对象。当客户端需要一个对象时,工厂首先检查是否已经存在具有相同内部状态的对象。如果存在,则返回现有的对象;如果不存在,则创建一个新的对象并将其添加到对象池中。

      • 客户端:通过享元工厂获取享元对象,并传递外部状态给享元对象,以便在具体的操作中使用。

    • 缓存(Map)

      • 缓存管理:通常由一个简单的Map实现,键(Key)是缓存的标识,值(Value)是缓存的数据。缓存管理器负责存储和检索缓存数据。

      • 客户端:直接通过键从缓存中获取数据,如果缓存中没有数据,则从数据库或其他数据源获取并存储到缓存中。


http://www.kler.cn/a/507323.html

相关文章:

  • 【Uniapp-Vue3】uni-api交互反馈showToast的使用方法
  • LabVIEW与WPS文件格式的兼容性
  • BIO、NIO、AIO
  • springCloudGateway+nacos自定义负载均衡-通过IP隔离开发环境
  • 【NLP】语言模型的发展历程 (1)
  • 26_Redis RDB持久化
  • ‌OCP英文全称是什么
  • ElementTree 库该怎么学习?
  • 华为EulerOS 学习,是否要先 RHCE?
  • Apache NiFi存在信息泄露漏洞(CVE-2024-56512)
  • Elasticsearch二次开发:实现实时定时同步同义词、近义词与停用词
  • Elasticsearch的function_score与rescore的区别
  • npm 方式安装Pyodide 详解
  • 小模型干大事情,基于LLaMA-Factory+Lora入门级微调开源AI模型
  • Windows远程桌面网关出现重大漏洞
  • redisson 连接 redis5报错 ERR wrong number of arguments for ‘auth‘ command
  • Android Studio:Linux环境下安装与配置
  • Maven私服+统一切换项目版本
  • 自动驾驶3D目标检测综述(八)
  • WebSocket 实时聊天
  • 机器学习——逻辑回归
  • CFD 预测中的机器学习:在 Benchmark 应用程序上使用 Stochos
  • 使用Newtonsoft.Json插件,打包至Windows平台显示不支持
  • vite vue 动态导入图片
  • 常用的C库函数与头文件
  • laravel10.x 框架中间件实现原理