【软考】设计模式之享元模式

本文介绍了享元设计模式,包括其在类结构稳定、频繁增加新操作场景中的应用,详细阐述了抽象享元、具体享元和享元工厂的角色,以及如何通过Java代码实现。重点展示了如何通过享元模式减少大量对象造成的存储开销。

1. 说明
  • 1.享元设计模式(Flyweight Design Pattern)是一种常见的软件设计模式
  • 2.属于结构型设计模式,对象结构型模式
  • 3.目的:运用共享技术有效地支持大量细粒度的对象
2. 应用场景
  • 1.类的结构改变较少,但经常要增加新的基于该结构的操作
  • 2.需要对某一对象结构的对象进行很多不同的并且不相关的操作,而需要避免让这些操作污染这些对象的类,也不希望在新增操作时修改这些类
3. 结构图

在这里插入图片描述

4. 构成
  • 1.享元模式的结构主要包含一下三个角色:抽象享元(Flyweight)角色、具体享元(Concrete Flyweight)角色和享元工厂(Flyweight Factory)角色
  • 2.抽象享元(Flyweight)角色:通常是一个接口或抽象类,在其中声明了具体享元类公共的方法。这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以设置外部数据(外部状态)。抽象享元角色规定了享元对象的统一接口,使得客户端可以透明地使用具体享元对象。
  • 3.具体享元(Concrete Flyweight)角色:实现了抽象享元类,为其内部状态提供了存储空间。通常,可以结合单例模式来设计具体享元类,为每个具体享元类提供唯一的对象。具体享元对象是可以共享的,它们存储了不会随环境改变而改变的可共享状态。
  • 4.享元工厂(Flyweight Factory)角色:负责创建和管理享元对象。当客户端请求一个享元对象时,享元工厂会检查是否已经存在具有相同内部状态的对象。如果存在,就返回已经存在的对象;如果不存在,就创建一个新的具体享元对象。享元工厂通常提供一个存储享元对象的享元池,用于缓存已经创建的享元对象。
  • 5.并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子结点
  • 6.Client 维持一个对 Flyweight 的引用;计算或存储一个或多个 Flyweight 的外部状态。
5. 适用性
  • 1.一个应用程序使用了大量的对象
  • 2.完全由于使用大量的对象,造成很大的存储开销
  • 3.对象的大多数状态都可变为外部状态
  • 4.如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
  • 5.应用程序不依赖于对象标识。由于Flyweight对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值
6. java示例
  • 1.抽象享元角色声明了具体享元类公共的方法
package com.learning.flyweight.bullet;

/**
 * 子弹的抽象享元类
 */
public interface Bullet {
    /**
     * 开火
     */
    void fire();

    /**
     * 设置子弹位置
     * @param x
     * @param y
     */
    void setPosition(int x, int y);

    /**
     * 重置子弹
     */
    void reset();
} 
  • 2.具体享元角色
package com.learning.flyweight.bullet;

// 具体的子弹享元类
public class BulletImpl implements Bullet {
    private int x;
    private int y;

    @Override
    public void fire() {
        System.out.println("Bullet fired at position (" + x + ", " + y + ")");
    }

    @Override
    public void setPosition(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public void reset() {
        // 在这里重置子弹的状态,例如将其位置设置为默认值
        this.x = 0;
        this.y = 0;
        // 可以添加其他需要重置的字段或状态
    }
}
  • 3.享元工厂角色
package com.learning.flyweight.bullet;

import java.util.ArrayList;
import java.util.List;

// 子弹工厂(享元工厂)
class BulletFactory {
    private List<Bullet> list = new ArrayList<>();
  
    // 获取子弹对象  
    public Bullet getBullet() {  
        if (!list.isEmpty()) {
            // 如果有可用的子弹(即已经回收的子弹),则重用  
            Bullet bullet = list.remove(list.size() - 1);
            bullet.reset(); // 重置子弹状态  
            return bullet;  
        } else {  
            // 如果没有可用的子弹,则创建一个新的子弹  
            return new BulletImpl();  
        }  
    }  
  
    // 回收子弹对象  
    public void recycleBullet(Bullet bullet) {
        list.add(bullet); // 将子弹添加到池中以便将来重用
    }  
}  
  • 4.客户端
package com.learning.flyweight.bullet;

public class Client {

    public static void main(String[] args) {
        BulletFactory bulletFactory = new BulletFactory();
        Bullet bullet = bulletFactory.getBullet();
        bullet.setPosition(100, 200);
        bullet.fire();
        // 一段时间后回收子弹(这里假设子弹在发射后立即回收)

        bulletFactory.recycleBullet(bullet);
        bullet = bulletFactory.getBullet();
        bullet.setPosition(50, 250);
        bullet.fire();
        // 一段时间后回收子弹(这里假设子弹在发射后立即回收)
        bulletFactory.recycleBullet(bullet);
    }
}

  • 5.示例截图
    在这里插入图片描述
### 中的23种设计模式详解 #### 创建型设计模式 创建型设计模式主要关注对象的创建过程,通过抽象化和封装来减少硬编码依赖。 1. **抽象工厂(Abstract Factory)** - 提供了一组用于创建一系列相关或相互依赖的对象的接口,而无需指定它们具体的类。这种模式适用于需要跨多个产品族创建对象的情况[^1]。 2. **工厂方法(Factory Method)** - 定义了一个用于创建对象的接口,但由子类决定实例化的具体类。这种方式将对象的创建延迟到了子类实现中,从而提高了灵活性和可扩展性[^3]。 3. **单例(Singleton)** - 确保某一个类只有一个实例,并提供全局访问点。常用于管理共享资源,比如配置文件或数据库连接池[^1]。 4. **生成器(Builder)** - 将复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示形式。特别适合于处理具有大量可选参数的对象初始化场景[^2]。 5. **原型(Prototype)** - 使用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。这种方法对于性能优化非常有用,尤其是在频繁克隆的情况下[^1]。 --- #### 结构型设计模式 结构型设计模式主要用于简化复杂的结构关系,提高系统的模块性和重用性。 1. **适配器(Adapter)** - 将不兼容的接口转换成客户端期望的形式,允许原本无法一起工作的类协同工作[^1]。 2. **桥接(Bridge)** - 将抽象部分与其实现部分分离开来,从而使两者都可以独立变化。这有助于降低耦合度并增强系统的可维护性。 3. **组合(Composite)** - 使客户以统一的方式对待单个对象以及对象容器,通常用来描述树形结构的数据层次体系。 4. **装饰器(Decorator)** - 动态地给某个对象增加额外的功能,而不影响其他同类对象的行为。这是一种替代继承的方式来扩展功能的有效手段[^1]。 5. **外观(Facade)** - 提供了一个简化的接口,隐藏了底层系统组件之间的复杂交互细节,降低了外部调用者的认知负担。 6. **享元(Flyweight)** - 主要目的是通过共享技术有效地支持大量的细粒度对象,尤其在内存有限时能显著提升效率[^1]。 7. **代理(Proxy)** - 为另一个对象提供一种控制机制,以便间接访问该对象。它可以用于远程服务调用、缓存或者权限验证等场合[^1]。 --- #### 行为型设计模式 行为型设计模式专注于对象间的职责分配和通信方式。 1. **责任链(Chain of Responsibility)** - 避免请求发送者与接收者之间形成固定的绑定关系,允许多个潜在接受者按顺序尝试处理同一个请求。 2. **命令(Command)** - 将请求封装成对象,从而可以用不同请求对客户端进行参数化;也可以支持撤销操作等功能。 3. **解释器(Interpreter)** - 对于简单的语法表达式,可以通过定义其语言的文法规则并通过递归算法求解语句含义。 4. **迭代器(Iterator)** - 提供一种遍历集合元素的方法,而又不需要暴露集合内部的具体表现形式。 5. **中介者(Mediator)** - 减少对象间直接联系的数量,引入中间层负责协调各参与者之间的协作逻辑[^1]。 6. **备忘录(Memento)** - 不破坏封装性的前提下捕获当前状态保存起来,之后再恢复到之前的状态[^1]。 7. **观察者(Observer)** - 当被观察目标发生改变时自动通知所有注册过的观察者更新自己的数据[^1]。 8. **状态(State)** - 允许对象在其内部状态发生变化时调整它的行为,仿佛改变了自身的类一样[^1]。 9. **策略(Strategy)** - 定义了一系列算法并将每一个都封装起来,使得他们可以互换使用,达到运行期间动态切换的目的。 10. **模板方法(Template Method)** - 在父类中定义好整个流程框架,把某些特定步骤留给子类去完成,既保留核心不变又给予足够的自由空间定制差异之处[^1]。 11. **访问者(Visitor)** - 添加新操作变得容易,因为只需要新增加一个新的访问者即可覆盖现有所有的节点类型。 --- ```python class SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] class Singleton(metaclass=SingletonMeta): pass singleton_instance_1 = Singleton() singleton_instance_2 = Singleton() print(singleton_instance_1 is singleton_instance_2) # True ``` --- #### 总结 以上就是中常见的23种经典设计模式及其基本概念介绍。每种模式都有各自适用范围及优缺点分析,在实际开发过程中应根据需求合理选用合适的解决方案。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

王佑辉

老板,赏点吧

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

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

打赏作者

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

抵扣说明:

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

余额充值