( 十二 ) 设计模式 之装饰器模式(Decorator)
( 十二 ) 设计模式 之装饰器模式(Decorator)
1、简介
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。在面向对象的设计中,有一条基本的规则就是“尽量使用对象组合,而不是对象继承”来扩展和复用功能。
装饰模式的思考起点就是这个规则。就增加功能来说,装饰模式比通过继承生成子类更为灵活。
组合的优点:
- 首先可以有选择地复用功能,不是所有被继承的功能都会被复用。
- 其次在转调前后,可以实现一些功能处理,而且对于原对象是透明的,也就是原对象并不知道在A方法处理的时候被追加了功能。
- 还有一个额外的好处,就是可以组合拥有多个对象的功能,而对于继承,Java只支持单继承,而且改变了原有类的继承结构。
2、装饰器模式的结构与实现
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰器模式的目标。下面来分析其基本结构和实现方法。
1. 模式的结构
在装饰模式的实现中,为了能够实现和原来使用被装饰对象的代码无缝结合,是通过定义一个抽象类,让这个类实现与被装饰对象相同的接口,然后在具体实现类中,转调被装饰的对象,在转调的前后添加新的功能,这就实现了给被装饰对象增加功能。在转调的时候,如果觉得被装饰对象的功能不再需要了,还可以直接替换掉,也就是不再转调,而是在装饰对象中完成全新的实现。
装饰器模式主要包含以下角色:
- Component: 组件对象的抽象(接口或抽象类),可以给具体的对象动态地添加职责。
- ConcreteComponent: 具体的组件对象,实现组件对象接口或者继承组件对象,通常就是被装饰器装饰的原始对象,也就是可以给这个对象添加职责。
- Decorator: 所有装饰器的抽象父类,需要实现组件Component接口,并持有一个 Component对象,其实就是持有一个被装饰的对象。
- ConcreteDecorator: 实际的装饰器对象,实现具体要向被装饰对象添加的功能。
装饰器模式的结构图如图 1 所示
2. 模式的实现
装饰器模式的实现代码如下:
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
// 创建一个接口:
public interface Shape {
void draw();
}
// 创建实现接口的实体类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
// 创建实现了 Shape 接口的抽象装饰类。
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
// 创建扩展了 ShapeDecorator 类的实体装饰类。
public 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");
}
}
使用 RedShapeDecorator 来装饰 Shape 对象。
public static void main(String[] args) {
ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
redCircle.draw();
redRectangle.draw();
}
3、装饰器模式的优缺点
优点
比继承更灵活: 从为对象添加功能的角度来看,装饰模式比继承更灵活。继承是静态的,而目一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器当中,
然后通过对象组合的方式,在运行时动态地组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能来决定的。
灵活性和可扩展性:装饰器模式可以灵活地组合和扩展类的功能,可以根据需要添加或删除装饰器,从而改变对象的行为。
缺点
实现复杂度较高: 装饰器模式需要在原有的类上添加一个接口,并在接口中定义了和原有类相同的方法,同时还需要实现一个装饰器类来扩展原有类的功能,这使得代码实现起来较为复杂。