【設計模式】裝飾器模式


使用頻率:★★★☆☆

一、什么是裝飾模式

通過關聯機制給類增加行為,其行為的擴展由修飾對象來決定;

如JAVA IO流里的以下形式,BufferedReader為裝飾類,其關聯了一個具體對象(new FileReader(new File("test.txt"))),並對其進行裝飾,裝飾后擁有readLine行為(方法):

new BufferedReader(new FileReader(new File("test.txt")));

二、補充說明

與繼承相似,不同點在於繼承是在編譯期間擴展父類,而裝飾器模式在運行期間動態擴展原有對象;

或者說,繼承是對類進行擴展,裝飾模式是對對象進行擴展;

三、角色

抽象構件

具體構件

抽象裝飾類

具體裝飾類

說明:具體構件、抽象裝飾類、具體裝飾類的共同父類是抽象構件,具體裝飾類繼承抽象裝飾類並在運行期間裝飾具體構件;

四、例子

例子說明:

畫家接口Painter,為抽象構件,有兩個方法,獲取畫家描述信息及繪畫;

PaintBeginner實現Painter接口,為具體構件;

PainterDecorator實現Painter接口,為抽象裝飾類,其內部關聯一個Painter對象,通過構造函數獲取;

HillPainterDecorator、RiverPainterDecorator、TreePainterDecorator為具體裝飾類,表明被裝飾的畫家能夠繪畫Hill、River、Tree;

類圖:

代碼實現:

Painter.java

package com.pichen.dp.decorator;

public interface Painter {


    public abstract String getDescription();
    
    public abstract String painting();
    
}
View Code

PaintBeginner.java

package com.pichen.dp.decorator;

public class PaintBeginner implements Painter{

    @Override
    public String getDescription() {

        return "";
    }

    @Override
    public String painting() {
        /* do nothing */
        return "";
    }

}
View Code

PainterDecorator.java

package com.pichen.dp.decorator;

public abstract class PainterDecorator implements Painter{

    private Painter decoratedPainter;
    public PainterDecorator(Painter decoratedPainter) {
        this.decoratedPainter = decoratedPainter;
    }
    
    public Painter getPainter(){
        return this.decoratedPainter;
    }
}
View Code

HillPainterDecorator.java

package com.pichen.dp.decorator;

public class HillPainterDecorator extends PainterDecorator{

    public HillPainterDecorator(Painter paper) {
        super(paper);
    }

    
    
    @Override
    public String getDescription() {
        return this.getPainter().getDescription() + "can paint hill, ";
    }

    @Override
    public String painting() {
        /* painting the hill */
        return this.getPainter().painting() + paintingHill();
    }
    
    public String paintingHill(){
        return "Hill, ";
    }

}
View Code

RiverPainterDecorator.java

package com.pichen.dp.decorator;

public class RiverPainterDecorator extends PainterDecorator{

    public RiverPainterDecorator(Painter paper) {
        super(paper);
    }

    @Override
    public String getDescription() {
        return this.getPainter().getDescription() + "can paint river, ";
    }

    @Override
    public String painting() {

        /* painting the river */
        return this.getPainter().painting() + paintingRiver();
    }
    
    public String paintingRiver(){
        return "River, ";
    }

}
View Code

TreePainterDecorator.java

package com.pichen.dp.decorator;

public class TreePainterDecorator extends PainterDecorator{

    public TreePainterDecorator(Painter paper) {
        super(paper);
    }

    @Override
    public String getDescription() {
        return this.getPainter().getDescription() + "can paint tree, ";
    }

    @Override
    public String painting() {
        /* painting the tree */
        return this.getPainter().painting() + paintingTree();
    }
    
    public String paintingTree(){
        return "Tree, ";
    }

}
View Code

Main.java

package com.pichen.dp.decorator;

public class Main {

    public static void main(String[] args) {
        
        Painter p0 = new PaintBeginner();
        System.out.println("Painter description:" + p0.getDescription());
        System.out.println("Painting:" + p0.painting() + "\n");

        HillPainterDecorator p2 = new HillPainterDecorator(new PaintBeginner());
        System.out.println("Painter description:" + p2.getDescription());
        System.out.println("Painting:" + p2.painting());
        System.out.println("Painting:" + p2.paintingHill() + "\n"); //新增的行為
        
        RiverPainterDecorator p3 = new RiverPainterDecorator(new PaintBeginner());
        System.out.println("Painter description:" + p3.getDescription());
        System.out.println("Painting:" + p3.painting());
        System.out.println("Painting:" + p3.paintingRiver() + "\n"); //新增的行為
        
        HillPainterDecorator p4 = new HillPainterDecorator(new RiverPainterDecorator(new TreePainterDecorator(new PaintBeginner())));
        System.out.println("Painter description:" + p4.getDescription());
        System.out.println("Painting:" + p4.painting());
        System.out.println("Painting:" + p4.paintingHill() + "\n"); //新增的行為

        
        

    }

}

執行結果如下,PaintBeginner類的對象未裝飾前,無行為;在被裝飾器裝飾后,行為可以改變:

五、JAVA IO流與裝飾模式

這里簡單的以Reader、BufferedReader、FileReader舉個例子,如下代碼:

        BufferedReader br = new BufferedReader(new FileReader(new File("test.txt")));
        br.readLine();

說明:

其中BufferedReader與FileReader有一個共同抽象父類Reader,Reader為抽象構件;

new FileReader(new File("test.txt"))為具體構件,運行期間被修飾的對象;

BufferedReader為具體修飾類,運行期間修飾具體構件;

裝飾后,被修飾的對象新增的行為是擁有readLine方法;

ps:查看源碼,沒發現BufferedReader對應的抽象裝飾類,個人覺得沒有抽象裝飾類,裝飾模式也是可以正常工作的,抽象構件(Reader)可以由具體修飾類關聯;

另外,具體修飾類也可以作為基類,被其它類繼承的,繼承后的類同樣也是具體修飾類,如LineNumberReader就是繼承BufferedReader;

所以,上面語句還可以這樣寫(ps:只是舉例,其實沒必要用BufferedReader修飾,直接LineNumberReader裝飾下就可以):

        BufferedReader br = new LineNumberReader(new BufferedReader(new FileReader(new File("test.txt"))));
        br.readLine();

links:

裝飾器模式★★★☆☆

生成器or建造者模式★★☆☆☆

抽象工廠模式★★★★★

工廠方法模式★★★★★

簡單工廠模式★★★★☆


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM