【设计模式】享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享尽可能多的对象来有效支持大量细粒度的对象。这个模式主要用于减少内存使用和提高性能,特别是在需要创建大量相似对象的场景中。享元模式的核心思想是将对象的状态分为内在状态(Intrinsic State)和外在状态(Extrinsic State),其中内在状态存储在对象内部,并且对于所有引用该对象的地方都是相同的;而外在状态则由客户端管理并传递给对象。

享元模式的关键要素

  1. Flyweight (享元)

    这是一个接口或抽象类,声明了具体享元类应该实现的操作。

    它定义了哪些方法可以访问内在状态,以及如何接收外在状态。

    java

    深色版本

    public interface Flyweight {

    void operation(int extrinsicState);

    }

  2. ConcreteFlyweight (具体享元)

    实现 Flyweight 接口的具体类。

    包含内在状态,并且可能会根据传入的外在状态执行不同的操作。

    java

    深色版本

    public class ConcreteFlyweight implements Flyweight {

    private final String intrinsicState;

    public ConcreteFlyweight(String intrinsicState) {

    this.intrinsicState = intrinsicState;

    }

    @Override

    public void operation(int extrinsicState) {

    System.out.println("Intrinsic State = " + this.intrinsicState);

    System.out.println("Extrinsic State = " + extrinsicState);

    }

    }

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

    如果某些对象不能被共享,或者它们包含的全部是外在状态,则可以创建非共享的具体享元类。

    这些对象不会被池化管理,而是直接由客户端创建和销毁。

    java

    深色版本

    public class UnsharedConcreteFlyweight implements Flyweight {

    @Override

    public void operation(int extrinsicState) {

    // 操作逻辑

    }

    }

  4. FlyweightFactory (享元工厂)

    负责管理和创建享元对象。

    它通常维护一个享元对象的缓存(如 HashMap),以确保相同内在状态的对象只创建一次,并能在后续请求时返回已存在的实例。

    java

    深色版本

    import java.util.HashMap;

    import java.util.Map;

public class FlyweightFactory {

private final Map<String, Flyweight> flyweights = new HashMap<>();

复制代码
public Flyweight getFlyweight(String key) {
    return flyweights.computeIfAbsent(key, k -> new ConcreteFlyweight(k));
}

}

使用享元模式的好处

节省内存:通过共享不可变的部分,减少了内存占用。

提升性能:当需要频繁创建和销毁大量相似对象时,享元模式可以通过重用现有对象来加快程序运行速度。

简化对象管理:客户端只需要关心外在状态,而不需要处理每个对象的所有细节。

示例应用场景

文本编辑器中的字符格式:在一个大型文档中,如果每个字符都单独保存其字体、颜色等属性信息,将会消耗大量的内存。使用享元模式,可以将这些格式信息作为内在状态进行共享,而将字符位置等信息作为外在状态由客户端管理。

GUI 系统中的图标:对于 GUI 应用程序,可能有多个组件使用相同的图标。通过享元模式,可以确保每个唯一的图标只加载一次,并且可以在不同地方重复使用。

游戏开发中的敌人角色:在一些游戏中,同一类型的敌人角色可能具有相同的外观和行为。使用享元模式,可以将这些共同特征作为内在状态,而将位置、健康值等变化的数据作为外在状态。

注意事项

内外状态分离:正确区分内在状态和外在状态是成功应用享元模式的关键。内在状态应该是不可变的,而外在状态则是可变的并且由客户端提供。

线程安全问题:如果享元对象将在多线程环境中使用,必须确保内在状态的线程安全性。由于内在状态是不可变的,因此这通常不是问题,但仍然需要注意任何可能影响到对象共享的行为。

总之,享元模式适用于那些需要高效地管理大量相似对象的应用程序。通过合理利用对象共享机制,它可以显著降低系统资源消耗,同时保持良好的性能表现。

相关推荐
羊锦磊1 小时前
[ Mybatis 多表关联查询 ] resultMap
java·开发语言·数据库·mysql·mybatis
ZeroToOneDev4 小时前
Java(泛型和JUnit)
java·开发语言·笔记
迪尔~5 小时前
Apache POI中通过WorkBook写入图片后出现导出PDF文件时在不同页重复写入该图片问题,如何在通过sheet获取绘图对象清除该图片
java·pdf·excel
现在,此刻6 小时前
leetcode 11. 盛最多水的容器 -java
java·算法·leetcode
DKPT6 小时前
Java设计模式之开闭原则介绍与说明
java·设计模式·开闭原则
hyy27952276847 小时前
企业级WEB应用服务器TOMCAT
java·前端·tomcat
布朗克1687 小时前
Spring Boot项目通过Feign调用三方接口的详细教程
java·spring boot·feign
Arva .7 小时前
Spring基于XML的自动装配
xml·java·spring
帅得不敢出门9 小时前
Android Framework定制长按电源键关机的窗口
android·java·framework
fatfishccc9 小时前
循序渐进学 Spring (上):从 IoC/DI 核心原理到 XML 配置实战
xml·java·数据库·spring·intellij-idea·ioc·di