1. 程式人生 > >設計模式之裝飾者(Decorator)模式

設計模式之裝飾者(Decorator)模式

首先來看一個場景,如圖:

Decorator

工人分為很多種類,比如電工,管道工等等,同時又有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就相當於是一個裝飾者,即在執行修管道功能之前先說一句“你好”,

“裝飾者”模式應用的很多,比如在JavaIO操作中,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();
            }
        }
        }
    }

當然也有將“裝飾者”模式叫做“油漆工”模式!