【設計模式】裝飾器模式

使用頻率:★★★☆☆

1、什麼是裝飾模式

經過關聯機制給類增長行爲,其行爲的擴展由修飾對象來決定;html

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

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

2、補充說明

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

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

3、角色

抽象構件post

具體構件this

抽象裝飾類spa

具體裝飾類code

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

4、例子

例子說明:對象

畫家接口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類的對象未裝飾前,無行爲;在被裝飾器裝飾後,行爲能夠改變:

5、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建造者模式★★☆☆☆

抽象工廠模式★★★★★

工廠方法模式★★★★★

簡單工廠模式★★★★☆

相關文章
相關標籤/搜索