————— 第二天 —————
————————————
裝飾器模式都包含哪些核心角色呢?
1. Component接口
在我們上面的例子中,Component接口相當於汽車接口,所有的被包裝類、包裝類,都繼承於這個接口。
2. ConcreteComponent類
ConcreteComponent類是被包裝的實現類。在例子中,奔馳汽車、寶馬汽車、特斯拉汽車都屬於這個角色。
3. Decorator抽象類
所有的包裝類,都繼承自Decorator抽象類,而Decorator類又實現了Component接口,這麼做是爲了實現多層嵌套包裝。
4. ConcreteDecorator類
具體的包裝類,用於擴充被包裝類的功能,比如例子中的自動駕駛功能、飛行功能擴展。
這四大核心角色的關係是怎樣的呢?我們可以用裝飾器模式的UML類圖來表達:
首先是汽車接口,也就是Component這個角色,裏面定義了run這個行爲:
public interface Car {
void run();
}
接下來是各種汽車的實現類,也就是ConcreteComponent角色,不同的汽車對於run行爲有着不同的實現:
public class BenzCar implements Car{
@Override
public void run() {
System.out.println("奔馳開車了!");
}
}
public class BmwCar implements Car{
@Override
public void run() {
System.out.println("寶馬開車了!");
}
}
public class TeslaCar implements Car{
@Override
public void run() {
System.out.println("特斯拉開車了!");
}
}
下面是裝飾器的抽象類,也就是Decorator角色,這個角色包含了被裝飾的成員對象:
public class CarDecorator implements Car {
protected Car decoratedCar;
public CarDecorator(Car decoratedCar){
this.decoratedCar = decoratedCar;
}
public void run(){
decoratedCar.run();
}
}
或許有人會覺得奇怪,爲什麼裝飾器類也要實現Car接口呢?這正是裝飾器模式的靈活之處。
繼承自Car接口,可以讓每一個裝飾器本身也可以被更外層的裝飾器所包裝,包裝的方式就是把Car對象作爲參數,傳入到外層裝飾器的構造函數當中。
接下來是具體的裝飾器實現類,也就是ConcreteDecorator角色。這些裝飾器同樣實現了run的行爲,一方面會調用被包裝對象的run方法,一方面會進行某些擴展操作(比如自動駕駛、飛行):
public class AutoCarDecorator extends CarDecorator {
public AutoCarDecorator(Car decoratedCar){
super(decoratedCar);
}
@Override
public void run(){
decoratedCar.run();
autoRun();
}
private void autoRun(){
System.out.println("開啓自動駕駛");
}}
public class FlyCarDecorator extends CarDecorator {
public FlyCarDecorator(Car decoratedCar){
super(decoratedCar);
}
@Override
public void run(){
decoratedCar.run();
fly();
}
private void fly(){
System.out.println("開啓飛行汽車模式");
}
}
最後,是我們的客戶端類。客戶端類負責創建被包裝對象和裝飾者,並決定如何進行包裝和執行:
public class Client {
public static void main(String[] args) {
Car benzCar = new BenzCar();
Car bmwCar = new BmwCar();
Car teslaCar = new TeslaCar();
//創建自動駕駛的奔馳汽車
CarDecorator autoBenzCar = new AutoCarDecorator(benzCar);
//創建飛行的、自動駕駛的寶馬汽車
CarDecorator flyAutoBmwCar = new FlyCarDecorator(new AutoCarDecorator(bmwCar));
benzCar.run();
bmwCar.run();
teslaCar.run();
autoBenzCar.run();
flyAutoBmwCar.run();
}
}
以輸入流爲例,爲了滿足不同輸入場景,JDK設計了多種多樣的輸入流,包括ByteArrayInputStream、FileInputStream等等。
這些輸入流都繼承自共同的抽象類:InputStream。
與此同時,爲了給這些輸入流帶來功能上的擴展,JDK設計了一個裝飾器類,FilterInputStream。該類繼承自InputStream,並且“組合”了InputStream成員對象。
從FilterInputStream類派生出了許多裝飾器子類,包括BufferedInputStream,DataInputStream等等,分別提供了輸入流緩衝,以及從輸入流讀取Java基本數據類型等額外功能。
—————END—————
喜歡本文的朋友,歡迎關注公衆號 程序員小灰,收看更多精彩內容
點個[在看],是對小灰最大的支持!