【设计模式】装饰器模式

使用频率:★★★☆☆

一、什么是装饰模式

通过关联机制给类增加行为,其行为的扩展由修饰对象来决定;

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

抽象工厂模式★★★★★

工厂方法模式★★★★★

简单工厂模式★★★★☆

posted @ 2016-01-31 19:42  风一样的码农  阅读(2902)  评论(0编辑  收藏  举报