1. 程式人生 > >java常用設計模式六:裝飾模式

java常用設計模式六:裝飾模式

一、概念

 裝飾模式可以在不改變一個物件本身功能的基礎上給物件增加額外的新行為。

基本角色:

  • 抽象構件:它是具體構件和抽象裝飾類的共同父類,聲明瞭在具體構件中實現的業務方法,它的引入可以使客戶端以一致的方式處理未被裝飾的物件以及裝飾之後的物件,實現客戶端的透明操作。
  • 具體構件:它是抽象構件類的子類,用於定義具體的構件物件,實現了在抽象構件中宣告的方法,裝飾器可以給它增加額外的職責(方法)。
  • 抽象裝飾類:它也是抽象構件類的子類,用於給具體構件增加職責,但是具體職責在其子類中實現。它維護一個指向抽象構件物件的引用,通過該引用可以呼叫裝飾之前構件物件的方法,並通過其子類擴充套件該方法,以達到裝飾的目的。
  • 具體裝飾類:它是抽象裝飾類的子類,負責向構件新增新的職責。每一個具體裝飾類都定義了一些新的行為,它可以呼叫在抽象裝飾類中定義的方法,並可以增加新的方法用以擴充物件的行為。

二、示例

 

   在沒有新增新行為之前,只有People(抽象構件)介面和2個子類Doctor(具體構件),Teacher(具體構件),都只有一個方法,內容就是“走路”。

   現在有新需求了:Doctor要一邊走路一邊唱歌,走路是原有的行為,唱歌是要新新增的行為。Teacher要一邊走路一邊哭,走路是原有的行為,唱歌是要新新增的行為。

   而且灰色的三個類是一個字不允許修改的,所以增加了綠色的裝飾類來實現新增職責的行為,Decorator(抽象裝飾類

)實現於People類,並且還持有People類作為成員,通過該成員,呼叫之前物件的方法。並且通過DoctorDecorator(具體裝飾類)和TeacherDecorator(具體裝飾類)來實現真正的增加的行為方法。

  1)抽象構件

public interface People {
    void walk();
}

2)具體構件

public class Doctor implements People {
    public void walk() {
        System.out.println("醫生走路");
    }
}
public
class Teacher implements People { public void walk() { System.out.println("老師走路"); } }

3)抽象裝飾類

public class Decorator implements People{
    private People people;
    public Decorator(People people){
        this.people = people;
    }

    public void walk() {
        if(people != null){
            people.walk();
        }
    }
}

4)具體裝飾類

public class DoctorDecorator extends Decorator {
    public DoctorDecorator(People people) {
        super(people);
    }
    @Override
    public void walk(){
        super.walk();//原來的行為
        doctorSing();//新增的行為
    }
    public void doctorSing(){
        System.out.println("醫生唱歌");
    }
}
public class TeacherDecorator extends Decorator {
    public TeacherDecorator(People people) {
        super(people);
    }
    @Override
    public void walk(){
        super.walk();//原來的行為
        teacherCry();//新增的行為
    }
    public void teacherCry(){
        System.out.println("老師哭泣");
    }
}

5)測試客戶端類

public class Client {
    public static void main(String[] args){
        System.out.println("原來的介面輸出以下內容=============================");
        People doctor = new Doctor();
        doctor.walk();
        People teacher =  new Teacher();
        teacher.walk();

        System.out.println("增加新的行為後輸出以下內容=============================");
        People doctorDecorator = new DoctorDecorator(doctor);
        People teacherDecorator = new TeacherDecorator(teacher);
        doctorDecorator.walk();
        teacherDecorator.walk();
    }
}
原來的介面輸出以下內容=============================
醫生走路
老師走路
增加新的行為後輸出以下內容=============================
醫生走路
醫生唱歌
老師走路
老師哭泣

 

三,總結

1.主要優點

  • 對於擴充套件一個物件的功能,裝飾模式比繼承更加靈活性,不會導致類的個數急劇增加。
  • 可以通過一種動態的方式來擴充套件一個物件的功能,通過配置檔案可以在執行時選擇不同的具體裝飾類,從而實現不同的行為。
  • 可以對一個物件進行多次裝飾,通過使用不同的具體裝飾類以及這些裝飾類的排列組合,可以創造出很多不同行為的組合,得到功能更為強大的物件。
  • 具體構件類與具體裝飾類可以獨立變化,使用者可以根據需要增加新的具體構件類和具體裝飾類,原有類庫程式碼無須改變,符合“開閉原則”。

2.主要缺點

  • 使用裝飾模式進行系統設計時將產生很多小物件,這些物件的區別在於它們之間相互連線的方式有所不同,而不是它們的類或者屬性值有所不同,大量小物件的產生勢必會佔用更多的系統資源,在一定程式上影響程式的效能。
  •  裝飾模式提供了一種比繼承更加靈活機動的解決方案,但同時也意味著比繼承更加易於出錯,排錯也很困難,對於多次裝飾的物件,除錯時尋找錯誤可能需要逐級排查,較為繁瑣