不學無數——裝飾模式

裝飾模式

在開始以前

咱們能夠用一個簡單的例子引出來裝飾模式,在小的時候,相信你們都有過這樣的經歷:小學每一年會有好幾回的考試,若是有一次成績很是差,並且考完之後學校會有個很損的招,就是打印出來成績單,而後讓家長簽字。那麼拿着這個成績單,確定是不會直接告訴家長成績什麼的,確定是會加一些,例如,語文考了65,就會說咱們班最高的才75。若是成績單沒有排名的話,那麼也會添油加醋的說排名靠前,這樣父母的就會被你說的所迷惑住,忽略了真實的成績。這樣說不定還會賞你點東西,而後大筆一揮一簽字,你也能夠鬆一口氣終於又混過一次了。程序員

其實這些東西均可以用類進行表示,類圖以下設計模式

成績報告圖

SchoolReport 類以下ide

abstract class SchoolReport{
    public abstract void report();
    public abstract void sign(String name);
}

FourGradesSchoolReport類以下學習

class FourGradesSchoolReport extends SchoolReport{

    @Override
    public void report() {
        System.out.println("尊敬的家長您好:");
        System.out.println("您孩子的成績以下: ");
        System.out.println("語文65 數學70 體育80");
    }

    @Override
    public void sign(String name) {
        System.out.println("家長簽名: "+name);
    }
}

Father類以下this

public static void main(String[] args) {
    SchoolReport schoolReport = new FourGradesSchoolReport();
    schoolReport.report();
    schoolReport.sign("張三");
}

固然這是學習好的同窗的作法,直接將成績單展現給家長就好,像考的差的就得加上上面的修飾了。類圖以下:.net

通過修飾的類圖

上面的兩個類不變,只是增長了修飾的類SougarFourGradesSchoolReport以下:設計

class SougarFourGradesSchoolReport extends FourGradesSchoolReport{

    private void reportHighScore(){
        System.out.println("此次考試語文最高成績是75,數學最高是80");
    }

    private void reportSort(){
        System.out.println("我在班級排名是20");
    }

    public void report(){
    	  //先彙報最高的成績
        this.reportHighScore();
        super.report();
        //而後彙報排名
        this.reportSort();
    }
}

就會發現輸出以下3d

此次考試語文最高成績是75,數學最高是80
尊敬的家長您好:
您孩子的成績以下: 
語文65 數學70 體育80
我在班級排名是20
家長簽名: 張三

直接經過繼承FourGradesSchoolReport此類確實能解決現有的問題,可是現實狀況是很是複雜的,若是是老爸當時喝多了直接看了成績單就直接簽字了、或者是聽完彙報最高成績之後就直接樂的直接簽字了,後面排名啥的都不看了、又或者是老爸想先看排名怎麼辦?繼續擴展?那會增長多少類?這仍是一個比較簡單的場景,若是須要裝飾的條件很是多的話,那麼每一個條件都進行擴展的話,那麼子類的數量會激增。並且後期維護也很差。代理

所以出現問題了,擴展性很差該怎麼辦?聰明的程序員們想到了一個辦法,專門定義一批負責裝飾的類,而後根據實際的狀況進行組裝裝飾。類圖以下:code

通過改進的類圖

此時的Decorator類以下

abstract class Decorator extends SchoolReport{
    private SchoolReport schoolReport;
    
    public Decorator(SchoolReport schoolReport){
        this.schoolReport = schoolReport;
    }
    
     @Override
     public void report() {
        this.schoolReport.report();
     }

     @Override
     public void sign(String name) {
        this.schoolReport.sign(name);
     }
 }

此時若是你瞭解代理模式的話,可能會有疑問,這和代理模式不是同樣嗎?帶着這個疑問讀下去。

此時的兩個修飾類HighSoreDecoratorSortDecorator以下

class HighScoreDecorator extends Decorator{

    public HighScoreDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }

    private void reportHighScore(){
        System.out.println("此次考試語文最高成績是75,數學最高是80");
    }

    public void report(){
        this.reportHighScore();
        super.report();
    }
}

class SortDecorator extends Decorator{

    public SortDecorator(SchoolReport schoolReport) {
        super(schoolReport);
    }

    private void reportSort(){
        System.out.println("我在班級排名是20");
    }

    public void report(){
        this.reportSort();
        super.report();
    }
}

此時在調用的時候就能夠進行隨意的裝飾,例如老爸想先聽最高分,而後直接簽名那麼調用以下

public static void main(String[] args) {
    SchoolReport schoolReport;
    schoolReport = new FourGradesSchoolReport();
    schoolReport = new HighScoreDecorator(schoolReport);
    schoolReport.report();
    schoolReport.sign("張三");
}

打印以下

此次考試語文最高成績是75,數學最高是80
尊敬的家長您好:
您孩子的成績以下: 
語文65 數學70 體育80
家長簽名: 張三

例如老爸想要先聽排名,而後聽最高成績,最後簽名,那麼調用以下

public static void main(String[] args) {
    //成績單拿過來
    SchoolReport schoolReport;
    //原裝的成績單
    schoolReport = new FourGradesSchoolReport();
    //加了最高分的成績單
    schoolReport = new HighScoreDecorator(schoolReport);
    //加了成績排名的成績單
    schoolReport = new SortDecorator(schoolReport);
    schoolReport.report();
    schoolReport.sign("張三");
}

打印以下

我在班級排名是20
此次考試語文最高成績是75,數學最高是80
尊敬的家長您好:
您孩子的成績以下: 
語文65 數學70 體育80
家長簽名: 張三

此時咱們若是想增長其餘的裝飾模式,只須要繼承了Decorator類便可,而後在使用的時候盡情組合就行。

裝飾模式定義

裝飾模式是動態的給一個對象添加一些額外的職責,就增長功能來講,裝飾模式相比生成子類更加靈活

裝飾模式的通用類圖以下

裝飾模式的通用類圖

在類圖中有四種角色須要說明

  • Component:Component是一個接口或者是抽象類,即定義咱們最核心的對象,也就是最原始的對象,如上面的成績單SchoolReport
  • ConcreateComponent:是最原始最基本的接口或者抽象類的實現,被裝飾的對象
  • Decorator:通常是一個抽象類,實現接口或者抽象方法,它裏面不必定有抽象的方法,可是它的屬性中必然有一個private變量指向Component抽象構件
  • ConcreteDecoratorAConcreteDecoratorB:兩個具體的裝飾類,在裏面須要寫所想裝飾的東西。

那麼接下來看裝飾類通用的實現

Component

abstract class Component{
    public abstract void operate();
}

具體的實現類ConcreateComponent

class ConcreateComponent extends Component{
    @Override 
    public void operate() {
        System.out.println("do something");
    }
}

抽象的裝飾類Decorator

abstract class Decorator extends Component {
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operate() {
        this. component. operate();
    }
}

具體的裝飾類ConcreteDecoratorAConcreteDecoratorB

class ConcreteDecoratorA extends Decorator{

    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    private void methodA(){
        System.out.println("MethodA裝飾");
    }
    
    public void operate(){
        this.methodA();
        super.operate();
    }
}

class ConcreteDecoratorB extends Decorator{

    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    private void methodB(){
        System.out.println("MethodB裝飾");
    }
    
    public void operate(){
        this. methodB();
        super.operate();
    }
}

此處須要主要原始方法和裝飾方法的執行順序在具體的裝飾類中時固定的,若是想要不一樣的順序能夠經過重載實現多種執行順序。

裝飾模式的優缺點

優勢

  • 裝飾類和被裝飾類能夠獨立發展,不會相互耦合,換句話說,Component類無需知道Decorator的類,Decorator類是從外部來擴展Component類的功能。
  • 裝飾模式是繼承關係的一個替代方案,咱們能夠看到在裝飾類中Decorator不管裝飾了多少層,返回的對象仍是Component
  • 裝飾模式能夠動態的擴展一個實現類的功能

缺點

只須要記住一點就好:複雜

裝飾模式和代理模式的區別

相信前面看完了裝飾模式會對裝飾模式有個簡單的理解,裝飾模式以對客戶透明的方式擴展對象功能,主要凸顯的是修飾、增長功能

而代理模式是給對象提供一個代理對象,並由代理對象來控制原有對象的引用,主要凸顯是控制功能。

參考文章

相關文章
相關標籤/搜索