1.为什么会有装饰器模式
当我们设计程序时,肯定会遇到原本设计的对象不满足当前业务的要求需要临时增强其功能的场景,在后期的代码维护和客户的需求变更常常会遇到这种问题,为了不改变原有的程序代码结果,这时候可以使用装饰器模式对原有对象进行增强。
在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式。
定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
2.使用场景
- 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
- 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰器模式却很好实现。
- 当对象的功能要求可以动态地添加,也可以再动态地撤销时。
装饰器模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
3.四要素
- 抽象组件:定义被装饰对象和装饰器对象的公共接口,是具体组件类的接口。
- 具体组件:被装饰的对象,需要添加新功能的对象。
- 抽象装饰器:继承或实现抽象组件,包含一个抽象组件对象,并定义了与抽象组件相同的方法,同时可以通过组合方式持有其他装饰器对象。
- 具体装饰器:实现了抽象装饰器接口,负责向抽象组件添加具体的新功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。
4.装饰器模式设计
我们通过下面的实例来演示装饰器模式的使用。
创建一个 Shape 接口和实现了 Shape 接口的实现类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量,RedShapeDecorator 是实现了 ShapeDecorator 的实现类,测试类使用 RedShapeDecorator 来装饰 Shape 对象。
装饰器UML图
Shape
public interface Shape {
void draw();
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
ShapeDecorator
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
测试
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red