「全网最细 + 实战源码案例」设计模式——享元模式

简介: 享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少大量相似对象的内存消耗。通过分离对象的内部状态(可共享、不变)和外部状态(依赖环境、变化),它有效减少了内存使用。适用于存在大量相似对象且需节省内存的场景。模式优点包括节省内存和提高性能,但会增加系统复杂性。实现时需将对象成员变量拆分为内在和外在状态,并通过工厂类管理享元对象。

核心思想

  • 享元模式(Flyweight Pattern)是一种结构型设计模式,主要用于减少程序中大量对象的内存消耗。该模式通过共享相同的数据来有效减少内存的使用,适用于对象非常多且可以共享一部分状态的场景。
  • 核心:将对象的内部状态外部状态分离
    • 内部状态:存储在享元对象内部的、不会改变的状态,通常是可以共享的。
    • 外部状态:依赖于环境且变化的状态,不可共享。

编辑


结构

1. Flyweight(享元角色)

  • 声明享元对象的接口,通常是不可变的。

2. ConcretFlyweight(具体享元角色)

  • 实现 Flyweight 接口,存储共享状态。

3. UnsharedConcreteFlyweight(非共享具体享元角色)

  • 非共享的享元对象,一般不是由享元工厂创建。

4. FlyweightFactory(享元工厂)

  • 用来管理享元对象的工厂类,确保共享对象的唯一性。

编辑


适用场景

  1. 存在大量相似对象
  2. 对象状态可分为内部、外部状态
  3. 节省内存,避免重复创建对象。

优缺点

优点:

  1. 节省内存:避免重复创建相似对象。
  2. 提高性能:减少重复创建对象的开销。

缺点:

  1. 增加复杂性:享元模式、工厂类的设计。

实现步骤

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

示例

编辑

编辑

// 享元角色
public abstract class AbstractBox {

    // 获取图形
    public abstract String getShape();

    // 显示图形及颜色
    public void display(String color){
        System.out.println("方块:" + getShape() + ",颜色:" + color);
    }
}

// 具体享元角色——I
public class IBox extends AbstractBox{
    @Override
    public String getShape() {
        return "I";
    }
}

// 具体享元角色——L
public class LBox extends AbstractBox{
    @Override
    public String getShape() {
        return "L";
    }
}

// 具体享元角色——O
public class OBox extends AbstractBox{
    @Override
    public String getShape() {
        return "O";
    }
}

// 享元工厂(静态内部类单例方式)
public class BoxFactory {

    // 享元对象池
    private Map<String, AbstractBox> boxes;

    // 私有化构造器
    private BoxFactory() {
        boxes = new HashMap<>();
        boxes.put("L", new LBox());
        boxes.put("I", new IBox());
        boxes.put("O", new OBox());
    }

    // 获取享元对象
    public AbstractBox getBox(String type) {
        return boxes.get(type);
    }

    // 创建静态内部类
    private static class SingletonHolder {
        private static final BoxFactory INSTANCE = new BoxFactory();
    }

    // 获取享元工厂实例
    public static BoxFactory getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {

        // 1.获取享元工厂
        BoxFactory boxFactory = BoxFactory.getInstance();

        // 2.获取享元对象
        AbstractBox box1 = boxFactory.getBox("L");
        AbstractBox box2 = boxFactory.getBox("I");
        AbstractBox box3 = boxFactory.getBox("O");
        AbstractBox box4 = boxFactory.getBox("O");

        // 3.获取非享元对象并显示
        box1.display("red");
        box2.display("blue");
        box3.display("green");
        box4.display("yellow");

        // 4.验证享元对象是否共享
        System.out.println(box3 == box4);

    }
}
AI 代码解读


在源码中的应用

编辑

编辑

编辑

编辑


与其他模式的关系

  • 你可以使用享元模式实现组合模式树的共享叶节点以节省内存。
  • 享元展示了如何生成大量的小型对象, 外观模式则展示了如何用一个对象来代表整个子系统。
  • 如果你能将对象的所有共享状态简化为一个享元对象, 那么享元就和单例模式类似了。 但这两个模式有两个根本性的不同。
    • 只会有一个单例实体, 但是享元类可以有多个实体, 各实体的内在状态也可以不同。
    • 单例对象可以是可变的。 享元对象是不可变的。

目录
打赏
0
90
92
0
176
分享
相关文章
Python 高级编程与实战:深入理解设计模式与软件架构
本文深入探讨了Python中的设计模式与软件架构,涵盖单例、工厂、观察者模式及MVC、微服务架构,并通过实战项目如插件系统和Web应用帮助读者掌握这些技术。文章提供了代码示例,便于理解和实践。最后推荐了进一步学习的资源,助力提升Python编程技能。
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
61 13
「全网最细 + 实战源码案例」设计模式——责任链模式
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
64 14
「全网最细 + 实战源码案例」设计模式——命令模式
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
65 8
「全网最细 + 实战源码案例」设计模式——策略模式
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
68 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
83 22
设计模式:工厂方法模式(Factory Method)
工厂方法模式是一种创建型设计模式,通过将对象的创建延迟到子类实现解耦。其核心是抽象工厂声明工厂方法返回抽象产品,具体工厂重写该方法返回具体产品实例。适用于动态扩展产品类型、复杂创建逻辑和框架设计等场景,如日志记录器、数据库连接池等。优点包括符合开闭原则、解耦客户端与具体产品;缺点是可能增加类数量和复杂度。典型应用如Java集合框架、Spring BeanFactory等。
「全网最细 + 实战源码案例」设计模式——生成器模式
生成器模式(Builder Pattern)是一种创建型设计模式,用于分步骤构建复杂对象。它允许用户通过控制对象构造的过程,定制对象的组成部分,而无需直接实例化细节。该模式特别适合构建具有多种配置的复杂对象。其结构包括抽象建造者、具体建造者、指挥者和产品角色。适用于需要创建复杂对象且对象由多个部分组成、构造过程需对外隐藏或分离表示与构造的场景。优点在于更好的控制、代码复用和解耦性;缺点是增加复杂性和不适合简单对象。实现时需定义建造者接口、具体建造者类、指挥者类及产品类。链式调用是常见应用方式之一。
63 12
|
2月前
|
「全网最细 + 实战源码案例」设计模式——模式扩展(配置工厂)
该设计通过配置文件和反射机制动态选择具体工厂,减少硬编码依赖,提升系统灵活性和扩展性。配置文件解耦、反射创建对象,新增产品族无需修改客户端代码。示例中,`CoffeeFactory`类加载配置文件并使用反射生成咖啡对象,客户端调用时只需指定名称即可获取对应产品实例。
92 40
「全网最细 + 实战源码案例」设计模式——工厂方法模式
简单工厂模式是一种创建型设计模式,通过一个工厂类根据传入参数创建不同类型的产品对象,也称“静态工厂方法”模式。其结构包括工厂类、产品接口和具体产品类。适用于创建对象种类较少且调用者无需关心创建细节的场景。优点是封装性强、代码复用性好;缺点是扩展性差,增加新产品时需修改工厂类代码,违反开闭原则。
56 15
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等