设计模式沉思录(九)之 装饰器模式
装饰器模式(Decorator Pattern)
允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
动态地给一个对象附加额外的职责。装饰者为功能的扩展提供了一个比使用子类继承更加灵活的选择
本文整理自四人帮著作:Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素)
介绍
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
在一个功能的基础上添加新功能,除了继承,我们还可以使用组合。即把A类当做B类的一个属性,在B类中使用A类的方法。从而实现B类对A类功能的继承。这种组合的模式比继承更加的灵活。这个就是装饰者模式的基础。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码: 1、Component 类充当抽象角色,不应该具体实现。 2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
应用实例:
1.IO流中。在InputStream外面套上一层InputStreamReader,再套上一层BufferedReader。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
注意事项:可代替继承。
实现
我们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
步骤 1 创建shape接口:
1 | public interface Shape { |
步骤 2 创建实现接口的 实体类Rectangle和Circle。
1 | public class Rectangle implements Shape { |
步骤 3 (关键)创建实现了 Shape 接口的 抽象装饰类
内部有个装饰对象属性,构造时需引入1
2
3
4
5
6
7
8
9
10
11public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;//内部有个装饰对象属性
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
步骤 4 (关键)创建扩展了 ShapeDecorator 类的 实体装饰类。
1 | public class RedShapeDecorator extends ShapeDecorator { |
步骤 5 使用 RedShapeDecorator 来装饰 Shape 对象。
1 | public class DecoratorPatternDemo { |
总结:
一般情况:新建shape接口,circle接口继承shape接口,redcirle实体类实现circle接口
装饰器模式:
1.新建shape接口,
2.抽象类ShapeDecorator实现shape接口,并且其构造方法接收shape实例。
3.RedShapeDecorator实体装饰类继承ShapeDecorator 类(不同的实现类可实现不同的,继承自shape的方法,以体现诸如color等特点)
优点:若我想修改color,则只需要修改RedShapeDecorator,不用修改shape。
同样,若我只想修改shape,也不用去修改color。
- Component接口
这个是一个抽象组件,是原始的最核心的接口,是被装饰者的抽象
ConcreteComponent类。
这个类实现了Component接口,是具体的被装饰组件。在这个是最核心,最原始,最基本的组件。是具体的被装饰的组件。他实现了Component接口中的核心Operation方法。
Decorator抽象类。
这类一般是个抽象类。是所有装饰者的父类,他实现了Component接口。它里面有一个私有的Component类型的属性!!!。在构造方法中初始化这个属性。在实现Component的Operation方法的时候调用的是他的Component属性的Operation方法。这个抽象类中这个组件就像上面的Decorator。
ConcreteDecorator类 装饰者具体实现类。
这个是具体的装饰者类。继承自Decorator类。并且在每一个ConcreteDecorator里中有一个私有的新功能方法。然后在重写父类的Operation方法的时候。可以根据新添加的方法的执行位置,在super.Operation()之前或者之后调用本类的修饰方法(就可以体现清除不同实现的区别了)。灵活的向被修饰的类中添加新功能。
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(path))));
与1
Shape redRectangle = new RedShapeDecorator(new Circle());
类似
IO流是 在path下的File中读出数据封装成一个FileInputStream流,然后被InputStreamReader装饰成一个Reader流,然后被BufferedReader装饰成为一个带缓冲的Reader。每一层封装都是对原始流的一次装饰,动态的 并且独立地 向原始的文件流中添加职责与功能。最后成为一种我们可以很方便的处理的流。