當前位置: 華文問答 > 動漫

漫畫設計模式:什麽是「裝飾器模式」?

2021-01-05動漫

————— 第二天 —————

————————————

裝飾器模式都包含哪些核心角色呢?

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基本數據型別等額外功能。

喜歡本文的朋友,歡迎關註微信公眾號 程式設計師小灰 ,收看更多精彩內容