設計模式之裝飾者(Decorator)模式
阿新 • • 發佈:2019-01-05
首先來看一個場景,如圖:
工人分為很多種類,比如電工,管道工等等,同時又有A公司的電工,B公司的電工,A公司的管道工,B公司的管道工等等,那麼當有M個工種和N個公司的時候,就會有 M * N 個子類,這個繼承體系就會變得很龐大和複雜。那麼如何簡化呢,那麼就使用“裝飾者”模式。
那麼首先寫一個Worker
的介面,然後在不同的工種中去實現它,並複寫其方法:
- Worker.java(工人的抽象介面)
interface Worker {
public void doSomeWork();
}
- Plumber.java(管道工的實現類)
public class Plumber implements Worker {
public void doSomeWork(){
System.out.println("修水管");
}
}
- Electrician.java(電工的實現類)
public class Electrician implements Worker {
public void doSomeWork(){
System.out.println("修電路");
}
}
現在,為了講求服務質量,假設A公司要求進到顧客家裡後說“你好”,而B公司要求進到客戶家裡後帶鞋套,那麼,按照之前的思想,我們需要再對管道工和電工分別建立兩個類,就是A公司的管道工,B公司的管道工,A公司的電工,B公司的電工,就像上面圖示的那樣。
- AWorker.java
class AWorker implements Worker {
//這裡就是最重要的核心:不僅加了一個worker成員變數,還加了一個建構函式
private Worker worker;
public AWorker(Worker worker){
this.worker = worker;
}
public void doSomeWork(){
System.out.println("你好");
worker.doSomeWork();
}
}
然後在主函式中:
public class Test {
public static void main(String[] args) {
//首先生成一個A公司管道工物件
Plumber plumber = new Plumber();
//plumber是實現了Worker的子類,因此可以向上轉型為worker傳入AWorker的引數中
AWorker aWorker = new AWorker(plumber);
aWorker.doSomeWork();
}
}
結果為:
那麼這樣做的好處就是,無論是什麼工種,只要是A公司的,那麼就必定會先執行“你好”這個行為,然後再執行自己的事情,由於傳入進去的是一個管道工的物件,那麼執行的行為就是管道工的行為,當需要電工執行時,只需生成一個電工物件和一個AWorker
物件,然後傳入即可,程式碼為:
public class Test {
public static void main(String[] args) {
Plumber plumber = new Plumber();
AWorker aWorker1 = new AWorker(plumber);
aWorker1.doSomeWork();
//傳入電工的物件
Electrician electrician = new Electrician();
AWorker aWorker2 = new AWorker(electrician);
aWorker2.doSomeWork();
}
}
顯示結果為:
因此,此處的AWorker就相當於是一個裝飾者,即在執行修管道功能之前先說一句“你好”,
“裝飾者”模式應用的很多,比如在Java
的IO
操作中,FileReader
是節點流,而BufferedReader
是處理流,BufferedReader
就是裝飾者,FileReader
就是被裝飾者,裝飾者是給被裝飾者新增功能的。程式碼如下,可以自行體會一下:
public class Test {
public static void main(String[] args) {
FileReader fileReader = null;
BufferedReader bufferedReader = null;
try {
//重點部分:fileReader是節點流,bufferedReader是處理流,
//bufferedReader是裝飾者,FileReader是被裝飾者,裝飾者給
//被裝飾者新增功能
fileReader = new FileReader("I:/user.txt");
bufferedReader = new BufferedReader(fileReader);
String line = null;
while(true){
line = bufferedReader.readLine();
if(line == null){
break;
}
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
當然也有將“裝飾者”模式叫做“油漆工”模式!