概念
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
和继承的区别
一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很多。
比如:我有一个轮子,有滚动的功能。现在,我想把它装在汽车上,有驾驶的功能。我想让我的汽车是红色的。这时候使用继承实现的话没问题,但是如果有一天我想要一个红色的轮子,把它装在汽车上,有驾驶的功能,汽车要蓝色的。这时候是不是要另外一种继承结构类。这样下去,就会产生很多的继承关系以及更多的子类。
优缺点
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:层装饰比较复杂。
场景
- 扩展一个类的功能。
- 动态增加功能,动态撤销。
Java中的IO流使用了装饰者模式,允许将低级别的IO接口封装成高级的IO接口。
UML
circle称为基础组件,Decorator子类称为装饰组件,基础组件只能被装饰,而装饰组件可以装饰基础组件,也可以装饰其它装饰组件,这就是为什么装饰组件和基础组件都要实现Shape接口的原因。
因此,被装饰对象可以是基础组件,也可以是一个装饰组件。
代码示例
Shape
两个作用:
- 作为标记接口,标记实现类的类型
- 定义统一的抽象方法,规范子类的行为
public interface Shape {
void draw();
}
基础组件
public class Circle implements Shape {
@Override
public void draw() {
System.out.print("a circle!");
}
}
装饰组件抽象类
这个类的主要作用是定义装饰行为,即在被装饰对象的已有能力之上,提供更多的能力,定义在draw。只是这种装饰行为是统一的,对所有的被装饰者而言,都是一样的。是不是看到了代理的影子!
public abstract class Decorator implements Shape {
protected Shape circle;
public Decorator(Shape shape) {
circle = shape;
}
public void draw() {
circle.draw();
}
}
具体装饰组件
public class CircleEdge extends Decorator {
public CircleEdge(Shape circle) {
super(circle);
}
private void setEdgeColor() {
System.out.print(", edge with color");
}
public void draw() {
circle.draw();
setEdgeColor();
}
}
public class CircleFill extends Decorator {
public CircleFill(Shape circle) {
super(circle);
}
private void setEdgeFill() {
System.out.print(", content with color");
}
public void draw() {
circle.draw();
setEdgeFill();
}
}
demo
public class Demo {
public static void main(String[] args) {
Shape circle = new Circle();
circle.draw();
System.out.println("");
Decorator circleEdge = new CircleEdge(circle);
circleEdge.draw();
System.out.println("");
Decorator circleFill = new CircleFill(circle);
circleFill.draw();
System.out.println("");
Decorator circleEdgeFill = new CircleFill(circleEdge);
circleEdgeFill.draw();
}
}
场景
装饰器模式最大的特点是基础组件和装饰组件接耦,并且存在一定的对等关系。但是,一次仅允许装饰最多一个基础组件,但是允许装饰多了装饰组件。这应该是划分基础组件和装饰组件的依据。