享元模式:運用共享技術有效支持大量細粒度對象的復用,通過區分內部狀態 (可共享) 與 外部狀態 (不可共享),大幅減少對象創建數量,降低記憶體佔用。
| 角色 | 職責 | 例子 |
|---|---|---|
| Flyweight (抽象享元) | 定義接口,聲明外部狀態設置/獲取方法 | Shape 接口 |
| ConcreteFlyweight (具體享元) | 實現接口,存儲內部狀態,實現業務邏輯 | Circle 類 (顏色為內部狀態) |
| UnsharedConcreteFlyweight (非共享享元) | 不要求共享的對象,可直接實例化 | 大尺寸圖片、上下文對象 |
| FlyweightFactory (享元工廠) | 管理享元池,提供獲取/創建享元的全局訪問點 | CircleFactory (Map<色彩, Circle>) |
| Client (客戶端) | 維護外部狀態,調用工廠獲取享元,調用享元操作 | 繪圖程序主邏輯 |
// 1. 抽象享元
interface Shape {
void draw(int x, int y, int radius); // 外部狀態作為參數傳入
}
// 2. 具體享元:圓形 (顏色為內部狀態)
class Circle implements Shape {
private final String color; // 內部狀態:不可變、可共享
public Circle(String color) { this.color = color; }
@Override
public void draw(int x, int y, int radius) {
System.out.printf("繪製 %s 圓:中心(%d,%d) 半徑%d%n", color, x, y, radius);
}
public String getColor() { return color; }
}
// 3. 享元工廠:管理色彩池
class ShapeFactory {
private static final Map<String, Shape> pool = new ConcurrentHashMap<>();
public static Shape getCircle(String color) {
return pool.computeIfAbsent(color, Circle::new); // 線程安全獲取/創建
}
public static int getPoolSize() { return pool.size(); }
}
// 4. 客戶端使用
public class DrawingApp {
private static final String[] COLORS = {"紅", "綠", "藍", "黃", "黑"};
private static final Random random = new Random();
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
String color = COLORS[random.nextInt(COLORS.length)];
int x = random.nextInt(100);
int y = random.nextInt(100);
int radius = random.nextInt(50) + 10;
Shape circle = ShapeFactory.getCircle(color); // 從池獲取
circle.draw(x, y, radius); // 傳入外部狀態
}
System.out.println("實際創建對象數: " + ShapeFactory.getPoolSize()); // 輸出 ≤ 5
}
}
| 類 | 享元對象 | 內部狀態 | 說明 |
|---|---|---|---|
String | 字符串常量 | 字符序列 | 字符串常量池 (String Pool),intern() 手動入池 |
Integer | -128 ~ 127 | 數值 | IntegerCache,valueOf() 自動復用 |
Boolean | TRUE/FALSE | 布爾值 | 單例模式實現 |
BigDecimal | 常用數值 | 數值、精度 | valueOf() 緩存零值等 |
| 數據庫連接池 | Connection | 連接參數 | HikariCP、Druid 等池化技術本質是享元 |
| 線程池 | Thread | 線程屬性 | ExecutorService 復用線程避免頻繁創建銷毀 |
// 當單個享元粒度太細,可組合成複合享元
class CompositeShape implements Shape {
private final List<Shape> shapes = new ArrayList<>();
public void add(Shape shape) { shapes.add(shape); }
@Override
public void draw(int x, int y, int radius) {
for (Shape s : shapes) s.draw(x, y, radius);
}
}
// 工廠返回複合對象
class ShapeFactory {
public static Shape getComposite(String... colors) {
CompositeShape composite = new CompositeShape();
for (String c : colors) composite.add(getCircle(c));
return composite;
}
}
a == b 不重要)享元模式是空間換時間的經典體現。核心在於狀態分離:將不變的內部狀態封裝在共享對象中,將變化的外部狀態由客戶端管理並在調用時傳入。JDK 集合框架、包裝類緩存、連接池/線程池均是該模式的工業級應用。適用於大量細粒度對象且內存敏感的場景。