一文弄懂23种设计模式之装饰器模式
Posted Java云海.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文弄懂23种设计模式之装饰器模式相关的知识,希望对你有一定的参考价值。
前言
装饰器模式
Reference
[2] c.biancheng.net/view/1397.h…
[3] refactoringguru.cn/design-patt…
什么是装饰器模式
装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
场景
假设你正在开发一个提供通知功能的库, 其他程序可使用它向用户发送关于重要事件的通知。
最初的版本基于 Notifier 类,用来接受客户端消息参数并发送给一系列邮箱,邮箱列表通过构造函数传递。
后续有新的需求增加, 用户要求能够在手机短信、微信、QQ上接收消息,那么可以这样做,扩展通知类,在子类中加入额外的通知方法,然后组合多种通知方法即可解决问题
弊端
- 系统扩展麻烦,在某些编程语言中无法实现,Java 中是不支持多继承的,所有每次要扩展一项功能,就必须新增一个类
- 代码重复,可以发现发送消息的代码在多个类中重复
- 系统庞大,类的数目非常多
解决方案
根本原因在于,这个设计的复用机制不合理,上图采用的是继承复用的机制,而我们知道,根据设计原则,应该多用组合,少用继承。
- 继承是静态的。 你无法在运行时更改已有对象的行为, 只能使用由不同子类创建的对象来替代当前的整个对象。
- 子类只能有一个父类。 大部分编程语言不允许一个类同时继承多个类的行为。
因此我们可以换个角度,将 send 方法这个通知行为放在基类通知器中,将所有其他方法放入装饰中。
这样,客户端代码就可以以装饰器的模式封装自己想要的功能
装饰模式结构
结构1
- 单个具体构件
- 没有抽象构件
如果只有一个具体构件而没有抽象构件时,可以让抽象装饰继承具体构件,也就是上面的 Notifier 的例子
结构2
- 只有一个具体装饰
如果只有一个具体装饰时,可以将抽象装饰和具体装饰合并
结构3
这个是经典的装饰器结构
- 有多个具体构件类
- 又有抽象构件类
- 部件,也叫抽象构件 (Component) 声明封装器和被封装对象的公用接口。
- 具体部件,也叫具体构件 (Concrete Component) 类是被封装对象所属的类。 它定义了基础行为, 但装饰类可以改变这些行为。
- 基础装饰 (Base Decorator) 类拥有一个指向被封装对象的引用成员变量。 该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象。
- 具体装饰类 (Concrete Decorators) 定义了可动态添加到部件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。
- 客户端 (Client) 可以使用多层装饰来封装部件, 只要它能使用通用接口与所有对象互动即可。
核心设计
装饰模式的核心在于抽象装饰类的设计,其典型代码如下所示:
class Decorator implements Component
//维持一个对抽象构件对象的引用
private Component component;
//注入一个抽象构件类型的对象
public Decorator(Component component)
this.component=component;
public void operation( )
component.operation( ); //调用原有业务方法
复制代码
在抽象装饰类Decorator中定义了一个Component类型的对象component,维持一个对抽象构件对象的引用,并可以通过构造方法或Setter方法将一个Component类型的对象注入进来,同时由于Decorator类实现了抽象构件Component接口,因此需要实现在其中声明的业务方法operation(),需要注意的是在Decorator中并未真正实现operation()方法,而只是调用原有component对象的operation()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。
在Decorator的子类即具体装饰类中将继承operation()方法并根据需要进行扩展,典型的具体装饰类代码如下:
class ConcreteDecorator extends Decorator
public ConcreteDecorator(Component component)
super(component);
public void operation()
super.operation(); //调用原有业务方法
addedBehavior(); //调用新增业务方法
//新增业务方法
public void addedBehavior()
……
复制代码
在具体装饰类中可以调用到抽象装饰类的operation()方法,同时可以定义新的业务方法,如 addedBehavior()
由于在抽象装饰类Decorator中注入的是Component类型的对象,因此我们可以将一个具体构件对象注入其中,再通过具体装饰类来进行装饰;此外,我们还可以将一个已经装饰过的Decorator子类的对象再注入其中进行多次装饰,从而对原有功能的多次扩展。
案例设计
Sunny软件公司基于面向对象技术开发了一套图形界面构件库VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特效显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能
直接利用装饰器模式,进行系统设计,使系统具有更好的灵活性和扩展性
具体代码
//抽象界面构件类:抽象构件类,为了突出与模式相关的核心代码,对原有控件代码进行了大量的简化
abstract class Component
public abstract void display();
//窗体类:具体构件类
class Window extends Component
public void display()
System.out.println("显示窗体!");
//文本框类:具体构件类
class TextBox extends Component
public void display()
System.out.println("显示文本框!");
//列表框类:具体构件类
class ListBox extends Component
public void display()
System.out.println("显示列表框!");
//构件装饰类:抽象装饰类
class ComponentDecorator extends Component
private Component component; //维持对抽象构件类型对象的引用
//注入抽象构件类型的对象
public ComponentDecorator(Component component)
this.component = component;
public void display()
component.display();
//滚动条装饰类:具体装饰类
class ScrollBarDecorator extends ComponentDecorator
public ScrollBarDecorator(Component component)
super(component);
public void display()
this.setScrollBar();
super.display();
public void setScrollBar()
System.out.println("为构件增加滚动条!");
//黑色边框装饰类:具体装饰类
class BlackBorderDecorator extends ComponentDecorator
public BlackBorderDecorator(Component component)
super(component);
public void display()
this.setBlackBorder();
super.display();
public void setBlackBorder()
System.out.println("为构件增加黑色边框!");
复制代码
客户端代码
class Client
public static void main(String args[])
Component component,componentSB,componentBB; //全部使用抽象构件定义
component = new Window();
componentSB = new ScrollBarDecorator(component);
//将装饰了一次之后的对象继续注入到另一个装饰类中,进行第二次装饰
componentBB = new BlackBorderDecorator(componentSB);
componentBB.display();
// 也可以这样写
Component component;
component = new BlackBorderDecorator( new ScrollBarDecorator( new Window( )));
复制代码
装饰器模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。
BufferedReader in = new BufferedReader(new FileReader("filename.txt"));
String s = in.readLine();
复制代码
小结
装饰器模式的主要优点有:
- 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰器模式完全遵守开闭原则
以上是关于一文弄懂23种设计模式之装饰器模式的主要内容,如果未能解决你的问题,请参考以下文章