Java設計模式--裝飾模式

裝飾模式【Decorator Pattern】
裝飾模式顧名思義就是將程序裝飾進行裝飾完成我們所想要的效果。山寨手機需要裝飾,我們的程序有時候也需要進行裝飾。
下面以向家長彙報分數讓家長簽字爲例。先看下最初的類圖。

這裏寫圖片描述

倘若這樣子直接拿給老爸看(直接彙報成績,要簽名),那豈不是要挨板子。對於差生來講,還得先裝飾一下好。
下面再看一下改善後的類圖。

這裏寫圖片描述

這樣子設計的話,就可以在report()方法中做點手腳了,可以先彙報一下最高分,畢竟老子跟最高分差了10來分而已。然後可以報告一下排名,畢竟全班60人我考了38,(其實已經退學了快20人了)。

程序設計如下:

public class SugarFouthGradeSchoolReport extends FouthGradeSchoolReport {
    //首先要定義你要美化的方法,先給老爸說學校最高成績
    private void reportHighScore(){
    System.out.println("這次考試語文最高是75,數學是78,自然是80");
    }
    //在老爸看完畢成績單後,我再彙報學校的排名情況
    private void reportSort(){
    System.out.println("我是排名第38名...");
    }
    //由於彙報的內容已經發生變更,那所以要重寫父類
    @Override
    public void report(){
    this.reportHighScore(); //先說最高成績
    super.report(); //然後老爸看成績單
    this.reportSort(); //然後告訴老爸學習學校排名
    }
}

這樣老爸看到的成績單已經是美化過的了:

public class Father {
public static void main(String[] args) {
    //美化過的成績單拿過來
    SchoolReport sr= new SugarFouthGradeSchoolReport();
    //看成績單
    sr.report();
    //然後老爸,一看,很開心,就簽名了
    sr.sign("老三"); //我叫小三,老爸當然叫老三
}

上面的例子通過繼承來解決這個問題,通過繼承只實現裝飾最高分這一項,倘若我們要裝飾得條件很多,那就會出問題了,出現類爆炸的情況。想想維護起來的成本。。。
我們還得好好裝飾一下,先看改善後的類圖:

這裏寫圖片描述

增加一個抽象類和兩個實現類,其中 Decorator 的作用是封裝 SchoolReport 類。

public abstract class Decorator extends SchoolReport{
    //首先我要知道是那個成績單
    private SchoolReport sr;
    //構造函數,傳遞成績單過來
    public Decorator(SchoolReport sr){
    this.sr = sr;
    }
    //成績單還是要被看到的
    public void report(){
    this.sr.report();
    }
    //看完畢還是要簽名的
    public void sign(String name){
    this.sr.sign(name);
    }
}

Decorator 的目的就是要讓子類來對SchoolReport 進行封裝。看下這麼封裝:

public class HighScoreDecorator extends Decorator {
    //構造函數
    public HighScoreDecorator(SchoolReport sr){
    super(sr);
    }
    //我要彙報最高成績
    private void reportHighScore(){
    System.out.println("這次考試語文最高是75,數學是78,自然是80");
    }
    //最高成績我要做老爸看成績單前告訴他,否則等他一看,就掄起笤帚有揍我,我那還有機會說呀
    @Override
    public void report(){
    this.reportHighScore();
    super.report();
    }
}
public class SortDecorator extends Decorator {
    //構造函數
    public SortDecorator(SchoolReport sr){
    super(sr);
    }
    //告訴老爸學校的排名情況
    private void reportSort(){
    System.out.println("我是排名第38名...");
    }
    //老爸看完成績單後再告訴他,加強作用
    @Override
    public void report(){
    super.report();
    this.reportSort();
    }
}

上面兩個子類重寫了report方法,達到了想要的結果。

老爸看成績單:

    SchoolReport sr;
    sr = new FouthGradeSchoolReport(); //原裝的成績單
    //加了最高分說明的成績單
    sr = new HighScoreDecorator(sr);
    //又加了成績排名的說明
    sr = new SortDecorator(sr);
    //看成績單
    sr.report();
    //然後老爸,一看,很開心,就簽名了
    sr.sign("老三"); //我叫小三,老爸當然叫老三

通過這樣的裝飾模式就躲過了一頓海扁。

下面再看看其通用類圖。

這裏寫圖片描述

看類圖,Component 是一個接口或者是抽象類,就是定義我們最核心的對象,也就是最原始的對象,比
如上面的成績單,記住在裝飾模式中,必然有一個被提取出來最核心、最原始、最基本的接口或抽象類,就是 Component。

ConcreteComponent 這個事最核心、 最原始、 最基本的接口或抽象類的實現, 你要裝飾的的對象。

Decorator 一般是一個抽象類,實現接口或者抽象方法。

ConcreteDecoratorA 和 ConcreteDecoratorB 是兩個具體的裝飾類。

總結:
(1)裝飾者模式的存在,解決的問題主要就是繼承帶來的弊端,首先可能帶來的類是上面所說的類爆炸的問題。同時繼承的話由於子類必須繼承父類的方法,所以當中間類的方法改變時,那麼就會牽一髮動全身了,利用裝飾模式就可以將其進行分離,降低其耦合性,方便程序的擴展。

(2)繼承與裝飾模式的選取:選擇繼承還是裝飾模式時主要考慮類之間的繼承層數問題,如果只是一層,那可以考慮繼承,如果出現多層繼承的情況,那就應該考慮裝飾模式了。

發佈了46 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章