享元模式的原理的详细解析以及使用案例。

前言

享元模式的核心是共享细粒度对象,以减少内存使用和对象创建的开销。这和对象池有相似之处,但享元更侧重于共享内在状态,而将可变部分作为外部状态传递。

关键点包括内在状态和外在状态的区分,工厂类管理共享对象,以及如何实现对象的复用。

享元模式可以作为另一种工具,特别是在处理大量相似对象时。比如,游戏中大量重复的棋子类型,或者文档中的字符对象,这些场景下享元模式非常适用。

需要注意的是,享元模式适用于对象的大部分状态可以外部化的情况。如果对象的状态经常变化,可能不适合使用享元。此外,线程安全也是一个考虑点,因为共享对象可能被多个线程访问。

最后,总结适用场景和优缺点,帮助用户判断何时使用享元模式。例如,在需要处理大量相似对象且内存占用高时,享元模式能显著优化性能。但如果对象状态变化频繁或难以区分内外状态,可能不适用。


享元模式(Flyweight Pattern)原理详解

核心思想 :通过共享技术减少大量细粒度对象的创建开销,将对象的**内在状态(不变部分)外在状态(可变部分)**分离,仅存储一份内在状态,外在状态由客户端传递。

关键概念
  1. 内在状态(Intrinsic State)

    • 对象中不变的部分,可以被多个对象共享(如字体、颜色配置)。
    • 存储于享元对象内部。
  2. 外在状态(Extrinsic State)

    • 对象中随上下文变化的部分(如位置、尺寸)。
    • 由客户端在调用时传入,不存储在享元对象中。
  3. 享元工厂(Flyweight Factory)

    • 管理共享的享元对象池,确保相同内在状态的对象只创建一次。

享元模式结构

text 复制代码
+-------------------+         +---------------------+
|   Flyweight       |         | FlyweightFactory    |
+-------------------+         +---------------------+
| +operation(extr)  |<------->| -pool: Map<String,Flyweight> |
+-------------------+         | +getFlyweight(key)  |
          ^                  +---------------------+
          |                              
+-------------------+
| ConcreteFlyweight |
+-------------------+
| -intrinsicState   |
+-------------------+
| +operation(extr)  |
+-------------------+

代码示例:文本编辑器中的字符对象

假设需要渲染大量文本字符,每个字符的字体、颜色等属性固定(内在状态),但位置、大小可变(外在状态)。

1. 定义享元接口
java 复制代码
public interface CharacterFlyweight {
    void render(int x, int y); // 外在状态由参数传递
}
2. 实现具体享元类
java 复制代码
public class ConcreteCharacter implements CharacterFlyweight {
    // 内在状态(不变)
    private final char character;
    private final String font;
    private final String color;

    public ConcreteCharacter(char character, String font, String color) {
        this.character = character;
        this.font = font;
        this.color = color;
    }

    @Override
    public void render(int x, int y) {
        System.out.printf("Render '%s' at (%d,%d) with font=%s, color=%s\n",
                character, x, y, font, color);
    }
}
3. 实现享元工厂
java 复制代码
import java.util.HashMap;
import java.util.Map;

public class CharacterFactory {
    private static final Map<String, CharacterFlyweight> pool = new HashMap<>();

    public static CharacterFlyweight getCharacter(char c, String font, String color) {
        // 生成唯一键:组合内在状态
        String key = c + "-" + font + "-" + color;
        if (!pool.containsKey(key)) {
            pool.put(key, new ConcreteCharacter(c, font, color));
        }
        return pool.get(key);
    }
}
4. 客户端使用
java 复制代码
public class Client {
    public static void main(String[] args) {
        // 获取共享的享元对象
        CharacterFlyweight charA = CharacterFactory.getCharacter('A', "Arial", "Red");
        CharacterFlyweight charB = CharacterFactory.getCharacter('B', "Times New Roman", "Blue");
        CharacterFlyweight charA2 = CharacterFactory.getCharacter('A', "Arial", "Red"); // 复用 charA

        // 渲染字符,传递外在状态(位置)
        charA.render(10, 20);
        charB.render(30, 40);
        charA2.render(50, 60); // 复用 charA 的内在状态
    }
}
输出结果
text 复制代码
Render 'A' at (10,20) with font=Arial, color=Red
Render 'B' at (30,40) with font=Times New Roman, color=Blue
Render 'A' at (50,60) with font=Arial, color=Red

享元模式 vs. 对象池

特性 享元模式 对象池
目标 减少内存占用,共享不变状态 复用可变对象,减少创建开销
状态管理 内在状态共享,外在状态由客户端传递 对象状态可能被重置或复用
适用场景 大量相似对象,内在状态可分离(如字符、UI控件) 对象创建成本高(如数据库连接、线程)

适用场景

  1. 大量重复对象:如游戏中的粒子系统、文本编辑器中的字符。
  2. 内存敏感型应用:移动端或嵌入式系统。
  3. 不可变对象:如
相关推荐
景熙55238 小时前
15.Java 8 Stream 流入门到实战
java·开发语言·数据结构
wno7049 小时前
Spring Security权限控制
java·python·spring
云老大-阿里云国际站代理商9 小时前
华为云国际站服务代理商:NAT网关怎么配?多台ECS共用公网IP要注意什么
服务器·华为云·云计算
杨运交9 小时前
[071][验证码模块]基于Spring拦截器的验证码认证设计思想
java·后端·spring
Geek-Chow10 小时前
CountDownLatch in Java
java
SL_staff10 小时前
从RBAC到场景化授权:《无忧·企业文档》三级权限模型的技术实践解析
java·开源·产品
传奇开心果编程11 小时前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
SL_staff11 小时前
财务系统慎用低代码?从数据模型闭环看合规落地的技术实践
java·低代码·全栈
滕州市燕猫虎计算机科技工作室个体工商户11 小时前
IDEA:Command line is too long
java·ide·intellij-idea
步行cgn12 小时前
Spring p 命名空间注入详解
java·前端·spring