一、引言:從平面設計的“圖層”說起
在計算機平面設計軟件(如Photoshop、Figma)中,一個核心概念是“圖層”。你可以從一個基礎的形狀或圖像開始,然后不斷添加新的圖層——比如加上一個顏色疊加、一個描邊、一個投影或者一個濾鏡。每一個新添加的圖層都“裝飾”了下方所有圖層的綜合效果,最終呈現出復雜的視覺效果。這個思想,與軟件工程中的裝飾者模式不謀而合。
裝飾者模式是一種結構型設計模式,它允許你動態地為對象添加新功能,而無需修改其結構。它通過將對象放入包含行為的特殊包裝類中,以“裝飾”原始對象。
二、裝飾者模式的核心結構與圖解
讓我們通過一個平面設計場景來拆解這個模式的核心組件。
UML圖解示意(文字描述):
- 組件接口: 這是所有對象的根基,定義了最基礎的操作。
- 對應設計:
Graphic(圖形接口),聲明一個draw()方法。
- 具體組件: 實現了組件接口的基礎對象。
- 對應設計:
Circle(圓形類)、Rectangle(矩形類)。它們實現了draw()方法,繪制一個基礎的、無修飾的圖形。
- 裝飾者基類: 它也實現了
Graphic接口,并持有一個Graphic對象的引用。這是所有裝飾器的父類。
- 關鍵點: 它不改變核心行為,只是將調用轉發給持有的組件對象。
- 具體裝飾者: 繼承自裝飾者基類,負責添加新的功能。
- 對應設計:
BorderDecorator(邊框裝飾器):在調用draw()前/后,為圖形添加一個邊框。
ColorFillDecorator(顏色填充裝飾器):在繪制圖形前,為其填充特定顏色。
ShadowDecorator(陰影裝飾器):為圖形添加一個投影效果。
模式流程(類比Photoshop操作):
1. 你創建了一個 Circle 對象(一個空白圓形圖層)。
2. 你想要紅色填充,于是將 circle 對象傳入 new ColorFillDecorator(circle, "RED")。現在你得到一個具有填充功能的“包裝”對象。
3. 你想要加粗邊框,于是再將上一步的結果傳入 new BorderDecorator(filledCircle, "BLACK", 2)。
4. 你還想添加陰影,于是得到 shadowedGraphic = new ShadowDecorator(borderedCircle, 45)。
5. 調用 shadowedGraphic.draw() 時,它會像棧一樣從外到內執行:
* 先計算陰影位置(裝飾器A),
- 然后繪制邊框(裝飾器B),
- 接著填充紅色(裝飾器C),
- 最后繪制基礎的圓形(核心組件)。
整個過程,你沒有修改 Circle 類的任何代碼,卻通過層層“裝飾”,動態地組合出了復雜的功能。
三、Java代碼示例:構建可裝飾的圖形
`java
// 1. 組件接口
interface Graphic {
void draw();
}
// 2. 具體組件
class Circle implements Graphic {
@Override
public void draw() {
System.out.println("繪制一個基礎圓形");
}
}
// 3. 裝飾者基類(抽象)
abstract class GraphicDecorator implements Graphic {
protected Graphic decoratedGraphic; // 持有一個組件對象的引用
public GraphicDecorator(Graphic graphic) {
this.decoratedGraphic = graphic;
}
@Override
public void draw() {
decoratedGraphic.draw(); // 默認行為:轉發調用
}
}
// 4. 具體裝飾者
class BorderDecorator extends GraphicDecorator {
private String color;
private int width;
public BorderDecorator(Graphic graphic, String color, int width) {
super(graphic);
this.color = color;
this.width = width;
}
@Override
public void draw() {
// 先執行額外功能
System.out.println("添加" + width + "px寬," + color + "色的邊框");
// 再調用被裝飾對象的原始方法
super.draw();
}
}
class ColorFillDecorator extends GraphicDecorator {
private String fillColor;
public ColorFillDecorator(Graphic graphic, String fillColor) {
super(graphic);
this.fillColor = fillColor;
}
@Override
public void draw() {
System.out.println("填充顏色:" + fillColor);
super.draw();
}
}
// 5. 客戶端使用
public class DecoratorDemo {
public static void main(String[] args) {
System.out.println("=== 基礎圖形 ===");
Graphic circle = new Circle();
circle.draw();
System.out.println("\n=== 裝飾后的圖形 ===");
// 動態組合裝飾:一個帶紅色填充和黑色邊框的圓形
Graphic fancyCircle = new BorderDecorator(
new ColorFillDecorator(
new Circle(), "紅色"),
"黑色", 2);
fancyCircle.draw();
// 輸出順序:
// 添加2px寬,黑色的邊框
// 填充顏色:紅色
// 繪制一個基礎圓形
}
}`
四、裝飾者模式在計算機平面設計中的優勢
- 開閉原則的典范: 無需修改現有圖形類(如
Circle),就能通過創建新的裝飾器類(如GradientDecorator漸變裝飾器)來無限擴展功能。 - 動態組合優于靜態繼承: 使用繼承來為圖形添加所有可能的特性組合(如“紅色帶邊框圓形”、“藍色帶陰影矩形”)會導致類爆炸。而裝飾者模式通過運行時組合,靈活且優雅。
- 分離核心功能與修飾功能: 圖形類只關心最基礎的繪制邏輯,所有修飾性功能(樣式、特效)由獨立的裝飾器類負責,職責清晰。
- 順序靈活性: 裝飾的順序可以自由調整,就像調整圖層順序會產生不同視覺效果一樣。
五、
裝飾者模式將軟件設計中的“圖層”思想發揮得淋漓盡致。它通過嵌套包裝的方式,將核心對象與可選的修飾功能解耦,提供了一種極其靈活的動態擴展對象功能的途徑。在Java I/O流庫(如BufferedReader包裝FileReader)、Java GUI開發以及任何需要動態、透明地添加對象職責的場景中,都能看到它的身影。理解了這個模式,下次當你使用設計軟件的圖層功能時,或許會對代碼的抽象之美有更深的體會。