————— 第二天 —————
————————————
裝飾器模式都包含哪些核心角色呢?
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基本數據型別等額外功能。
喜歡本文的朋友,歡迎關註微信公眾號 程式設計師小灰 ,收看更多精彩內容