装饰者模式,又叫装饰器模式。它可以动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更灵活,同时装饰者模式也体现了OCP原则。
在客户端调用使用了装饰者模式的对象时,就好像在使用构造器层层包裹核心对象,层层装饰核心对象,因此叫做装饰者模式。
装饰者模式属于结构型设计模式。在JDK的IO流API中,就利用了装饰者模式:
以简单的形状和颜色为例。如何为不同的形状装饰新的颜色呢?
上图中,Shape和ShapeDecorator都是抽象类,一般情况下,装饰者模式中的顶层装饰器类(ShapeDecorator)一定要是抽象类,因为它需要维护被装饰者,并重写特定行为。客户端在调用的时候,并不会直接使用它,而是会使用具体的装饰器类(Red、White)。
Shape类在本例中是一个抽象类,实际上也可以是一个接口,主要看有没有需要维护的属性。接口中是不允许有属性的,所以如果需要维护一些公共属性,那么可以采用抽象类,而如果只是封装了行为,那么建议采用接口。
装饰者模式的精髓在于,装饰者模式将继承和组合两种技巧相结合。
继承的目的是为了可以在原来的位置上取代被装饰对象(前提是调用方使用的是父类引用)。
组合(采用构造器传入一个被装饰对象,并在内部维护这个对象属性)的目的是可以在核心对象的基础之上加以装饰,即保留原来的核心对象的特征和行为,只做扩展,不做修改(OCP原则)。
装饰器子类在重写被装饰者的特定行为时,一定要注意,根据业务是否需要严格遵守对原来对象行为的扩展,而不是修改。如果是只扩展不修改,那么一定要在抽象装饰器类中调用被装饰对象的方法,并在装饰器子类的方法中使用“super.”的形式间接调用被装饰者的方法,然后根据装饰需要,在调用的前后执行装饰逻辑。如果业务设计上允许对原有行为作出一些修改,那么其实并没有严格遵守OCP原则,这种情况下,抽象装饰器类的对原对象方法的调用可以视情况而定修改甚至忽略。后者违背OCP原则的方式不建议使用装饰者模式来完成。
/**
* 图形接口
*/
public abstract class Shape {
protected String name;
public abstract void draw();
public String getName() {
return name;
}
}
public class Circle extends Shape {
public Circle() {
name = "圆形";
}
@Override
public void draw() {
System.out.println(name);
}
}
public class Square extends Shape {
public Square() {
name = "正方形";
}
@Override
public void draw() {
System.out.println(name);
}
}
/**
* 装饰器抽象类
*/
public abstract class ShapeDecorator extends Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape shape) {
this.decoratedShape = shape;
}
@Override
public void draw() {
decoratedShape.draw();
}
}
public class Red extends ShapeDecorator {
public Red(Shape shape) {
super(shape);
}
@Override
public void draw() {
paint();
}
// 随意增加想要装饰在核心对象上的功能
private void paint() {
System.out.println("红色的" + decoratedShape.getName());
}
}
public class White extends ShapeDecorator {
public White(Shape shape) {
super(shape);
}
@Override
public void draw() {
paint();
}
private void paint() {
System.out.println("白色的" + decoratedShape.getName());
}
}
测试代码:
public class Client {
public static void main(String[] args) {
Shape redCircle = new Red(new Circle());
redCircle.draw();
Shape whiteCircle = new White(new Circle());
whiteCircle.draw();
Shape redSquare = new Red(new Square());
redSquare.draw();
Shape whiteSquare = new White(new Square());
whiteSquare.draw();
}
}
测试结果:
红色的圆形
白色的圆形
红色的正方形
白色的正方形
装饰者模式主要用于对现有对象添加新的功能,可在一定程度上代替继承关系,实现低耦合关系。与桥接模式类似,都是为了防止类的膨胀而引出的结构型设计模式。而且在思路上,与桥接模式呈现相反的类的依赖关系。
装饰者模式基于OCP原则,不改变原来对象的属性及行为,只做扩展。
它的类结构特点有两个:继承和组合。
其中:
继承的目的是为了可以在原来的位置上替代被装饰对象(前提是调用方使用的是父类引用)。
组合(采用构造器传入一个被装饰对象,并在内部维护这个对象属性)的目的是可以在核心对象的基础之上加以装饰,即保留原来的核心对象的特征和行为,只做扩展,不做修改(OCP原则)。
除了更好的实现对象功能的扩展和特性组合,但是如果扩展功能较多,被迫多层装饰,就会使代码变得较为复杂。