设计模式中,Flyweight 模式的理解和示例、以及Flyweight 模式 vs Singleton 模式 区别对比,一文详解。
Flyweight 模式 vs Singleton 模式
Flyweight 模式示例(完整)
import java.util.HashMap;
import java.util.Map;
// 享元类:Student
public class Student {
// 缓存池
private static final Map<String, Student> cache = new HashMap<>();
// 静态工厂方法
public static Student create(int id, String name) {
String key = id + "\n" + name;
// 查询缓存
Student std = cache.get(key);
if (std == null) {
// 未找到,创建新对象
System.out.println(String.format("create new Student(%s, %s)", id, name));
std = new Student(id, name);
cache.put(key, std);
} else {
// 缓存中存在
System.out.println(String.format("return cached Student(%s, %s)", std.id, std.name));
}
return std;
}
private final int id;
private final String name;
private Student(int id, String name) { // 私有构造器,保证通过工厂方法创建
this.id = id;
this.name = name;
}
public void show() {
System.out.println("Student{id=" + id + ", name=" + name + "}");
}
public static void main(String[] args) {
Student s1 = Student.create(1, "Alice");
Student s2 = Student.create(1, "Alice");
Student s3 = Student.create(2, "Bob");
s1.show();
s2.show();
s3.show();
// 验证共享对象
System.out.println("s1 == s2? " + (s1 == s2)); // true
System.out.println("s1 == s3? " + (s1 == s3)); // false
}
}
运行示例输出
create new Student(1, Alice)
return cached Student(1, Alice)
create new Student(2, Bob)
Student{id=1, name=Alice}
Student{id=1, name=Alice}
Student{id=2, name=Bob}
s1 == s2? true
s1 == s3? false
解释
- 缓存复用:相同 id+name 的 Student 对象只会创建一次,后续请求直接返回缓存实例。
- 不可变对象:Student 的 id 和 name 是 final 的,确保共享安全。
- 工厂方法:通过 Student.create() 创建对象,禁止直接 new Student(),确保使用缓存。
Flyweight vs Singleton 对比
| 特性 | Singleton(单例模式) | Flyweight(享元模式) |
|---|---|---|
| 目的 | 保证类只有一个实例,全局共享 | 支持大量细粒度对象共享,减少重复实例 |
| 对象数量 | 只有一个对象 | 多个对象,但相同状态共享实例 |
| 使用场景 | 配置管理、日志系统、线程池管理、全局服务实例 | 缓存、图形对象、不可变对象复用(如Integer.valueOf) |
| 关键点 | 构造器私有、静态实例、全局访问 | 不可变对象、工厂方法、内部缓存池 |
| 状态特点 | 全局唯一,无状态或可管理全局状态 | 可分为内部状态(共享)和外部状态(可变) |
| 内存占用 | 只占用一份内存 | 多个对象共享内存,节省重复创建 |
✅ 一句话总结:
- Singleton → “只有一个,全局共享”。
- Flyweight → “共享重复对象,多份对象复用相同实例”。
对比示意图
Singleton:
+-----------------+
| Singleton | <-- 全局唯一实例
+-----------------+
Flyweight:
+-----------------+ +-----------------+
| Flyweight obj |----> | Flyweight obj | <-- 多个共享实例
+-----------------+ +-----------------+
^
|
FlyweightFactory
维护缓存
具体示例对比
1️⃣ Singleton 示例:全局日志管理器
// 单例类:Logger
public class Logger {
private static Logger instance;
private Logger() {} // 私有构造器
public static Logger getInstance() {
if (instance == null) {
instance = new Logger();
}
return instance;
}
public void log(String msg) {
System.out.println("LOG: " + msg);
}
public static void main(String[] args) {
Logger l1 = Logger.getInstance();
Logger l2 = Logger.getInstance();
System.out.println(l1 == l2); // true
l1.log("Hello Singleton");
}
}
特点:
- 全局只有一个 Logger 实例。
- 无论程序哪里需要写日志,都用同一个实例,节省资源且统一管理。
2️⃣ Flyweight 示例:文字编辑器中的字符对象
import java.util.HashMap;
import java.util.Map;
// Flyweight 类:Char
class Char {
private final char symbol; // 内部状态(共享)
public Char(char symbol) {
this.symbol = symbol;
}
public void display(String color) { // 外部状态(可变)
System.out.println("Char: " + symbol + " in color " + color);
}
}
// Flyweight 工厂
class CharFactory {
private static final Map<Character, Char> pool = new HashMap<>();
public static Char getChar(char c) {
pool.putIfAbsent(c, new Char(c)); // 缓存共享对象
return pool.get(c);
}
}
public class Main {
public static void main(String[] args) {
Char c1 = CharFactory.getChar('A');
Char c2 = CharFactory.getChar('A'); // 共享 c1
Char c3 = CharFactory.getChar('B');
c1.display("red");
c2.display("blue"); // 外部状态不同,但共享同一个实例
c3.display("green");
System.out.println(c1 == c2); // true
System.out.println(c1 == c3); // false
}
}
特点:
- 相同字符只创建一个实例,多次使用直接复用。
- 外部状态(颜色)不同,不影响共享的内部状态。
- 节省内存,尤其适合大量重复对象。
3️⃣ 对比总结
| 特性 | Singleton | Flyweight |
|---|---|---|
| 对象数量 | 1 个全局实例 | 多个对象,但相同内部状态共享 |
| 是否共享 | 全局共享 | 部分共享(内部状态) |
| 使用方式 | Logger.getInstance() | CharFactory.getChar('A') |
| 核心目的 | 保证全局唯一性 | 节省内存、重复对象复用 |
| 外部状态 | 可变 | 由客户端传入,不影响共享对象 |
💡 直观理解:
- Singleton:想象办公室里只有 一个打印机,大家都用它。
- Flyweight:想象办公室里有很多员工在用相同型号的 笔,笔的型号共享,但每个人写的颜色不同。

浙公网安备 33010602011771号