0122_享元模式(Flyweight)
享元模式(Flyweight)
意图
运用共享技术有效地支持大量细粒度的对象,通过共享相似对象来减少内存使用和提高性能。
UML 图

优点
- 减少内存使用:通过共享相似对象,显著减少内存占用
- 提高性能:减少了对象创建和垃圾回收的开销
- 简化对象管理:集中管理共享对象,便于维护和扩展
- 支持大量对象:能够有效处理大量细粒度对象的情况
- 分离内在和外在状态:将不变的内在状态与变化的外在状态分离
缺点
- 增加系统复杂度:需要区分内在状态和外在状态,增加了设计复杂性
- 线程安全问题:共享对象需要保证线程安全,可能需要同步机制
- 可能影响性能:如果外在状态计算复杂,可能会抵消共享带来的性能优势
- 不适用于所有场景:只有当对象具有大量相似状态时才适用
代码示例
以机器人制造为例,不同类型的机器人共享相同的内部状态(型号、基础配置),而外部状态(位置、任务)各不相同:
1. 享元接口 (Flyweight Interface)
// 机器人接口 - 享元
public interface Robot {
void operate(String location, String task);
String getModel();
}
2. 具体享元 (Concrete Flyweight)
// 具体机器人类型 - 具体享元
public class ConcreteRobot implements Robot {
private String model; // 内在状态(共享)
private String baseConfiguration; // 内在状态(共享)
public ConcreteRobot(String model, String baseConfiguration) {
this.model = model;
this.baseConfiguration = baseConfiguration;
}
@Override
public void operate(String location, String task) {
System.out.println("🤖 机器人型号: " + model +
" | 位置: " + location +
" | 执行任务: " + task +
" | 基础配置: " + baseConfiguration);
}
@Override
public String getModel() {
return model;
}
}
3. 享元工厂 (Flyweight Factory)
// 机器人工厂 - 享元工厂
public class RobotFactory {
private static Map<String, Robot> robotPool = new HashMap<>();
public static Robot getRobot(String model, String baseConfiguration) {
String key = model + "-" + baseConfiguration;
if (!robotPool.containsKey(key)) {
robotPool.put(key, new ConcreteRobot(model, baseConfiguration));
System.out.println("创建新机器人: " + key);
} else {
System.out.println("重用现有机器人: " + key);
}
return robotPool.get(key);
}
public static int getRobotCount() {
return robotPool.size();
}
}
4. 客户端代码 (Client Code)
// 客户端使用享元对象
public class RobotDeploymentSystem {
public static void main(String[] args) {
// 部署大量机器人,但只创建少量共享对象
// 获取共享的机器人对象
Robot robot1 = RobotFactory.getRobot("T-800", "Standard");
Robot robot2 = RobotFactory.getRobot("T-800", "Standard"); // 重用
Robot robot3 = RobotFactory.getRobot("T-1000", "Advanced");
Robot robot4 = RobotFactory.getRobot("T-800", "Standard"); // 重用
Robot robot5 = RobotFactory.getRobot("T-1000", "Advanced"); // 重用
System.out.println("\n已创建机器人类型数量: " + RobotFactory.getRobotCount());
// 使用不同的外在状态
System.out.println("\n机器人部署情况:");
robot1.operate("工厂A", "装配零件");
robot2.operate("工厂B", "质量检测");
robot3.operate("实验室", "科学研究");
robot4.operate("仓库", "货物搬运");
robot5.operate("控制室", "监控系统");
// 部署更多机器人
System.out.println("\n部署更多机器人:");
for (int i = 0; i < 5; i++) {
Robot robot = RobotFactory.getRobot("T-800", "Standard");
robot.operate("位置" + i, "任务" + i);
}
System.out.println("\n最终创建的机器人类型数量: " + RobotFactory.getRobotCount());
}
}
在Java标准库中的应用
享元模式在Java标准库中有多种应用:
-
字符串常量池
String s1 = "hello"; // 从常量池获取 String s2 = "hello"; // 重用同一个对象 String s3 = new String("hello"); // 创建新对象 System.out.println(s1 == s2); // true - 同一个对象 System.out.println(s1 == s3); // false - 不同对象 -
包装类的缓存
Integer i1 = Integer.valueOf(127); // 使用缓存 Integer i2 = Integer.valueOf(127); // 重用缓存对象 Integer i3 = Integer.valueOf(128); // 创建新对象(超出缓存范围) System.out.println(i1 == i2); // true System.out.println(i1 == i3); // false -
线程池
ExecutorService executor = Executors.newFixedThreadPool(5); // 重用线程对象而不是频繁创建销毁 for (int i = 0; i < 10; i++) { executor.execute(() -> { System.out.println("任务执行中: " + Thread.currentThread().getName()); }); } executor.shutdown(); -
连接池
// 数据库连接池重用连接对象 DataSource dataSource = // 获取数据源 try (Connection conn = dataSource.getConnection()) { // 使用数据库连接 } // 连接返回到池中重用
总结
享元模式通过共享相似对象来优化大量细粒度对象的内存使用,特别适用于需要创建大量相似对象的场景。它将对象状态分为内在状态(共享)和外在状态(不共享),通过工厂模式管理共享对象。在机器人示例中,相同型号和配置的机器人共享同一个对象实例,只有位置和任务等外在状态不同,从而显著减少了内存占用。

浙公网安备 33010602011771号