【设计模式】装饰器模式
使用频率:★★★☆☆
一、什么是装饰模式
通过关联机制给类增加行为,其行为的扩展由修饰对象来决定;
如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(); }
PaintBeginner.java
package com.pichen.dp.decorator; public class PaintBeginner implements Painter{ @Override public String getDescription() { return ""; } @Override public String painting() { /* do nothing */ return ""; } }
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; } }
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, "; } }
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, "; } }
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, "; } }
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();