10-装饰模式

装饰模式

分析

  • 可以在不改变一个对象本身功能的基础上给对象增加额外的新行为(照片+相框 \longrightarrow 防潮、美观)

  • 是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系

  • 引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能

装饰模式的定义

image-20230211141426050

对象结构型模式

  • 以对客户透明的方式动态地给一个对象附加上更多的责任

  • 可以在不需要创建更多子类的情况下,让对象的功能得以扩展

装饰模式结构

image-20230211141537950
装饰模式包含以下4个角色:
  • Component(抽象构件)

  • ConcreteComponent(具体构件)

  • Decorator(抽象装饰类)

  • ConcreteDecorator(具体装饰类)

抽象构件类典型代码
1
2
3
public abstract class Component {
public abstract void operation();
}
具体构件类典型代码
1
2
3
4
5
public class ConcreteComponent  extends Component {
public void operation() {
//实现基本功能
}
}
抽象装饰类典型代码
1
2
3
4
5
6
7
8
9
10
11
12
public class Decorator extends Component {
private Component component; //维持一个对抽象构件对象的引用

//注入一个抽象构件类型的对象
public Decorator(Component component) {
this.component=component;
}

public void operation() {
component.operation(); //调用原有业务方法
}
}
具体装饰类典型代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}

public void operation() {
super.operation(); //调用原有业务方法
addedBehavior(); //调用新增业务方法
}

//新增业务方法
public void addedBehavior() {
……
}
}
实例类图

image-20230211142115337

image-20230211142132245

(1) Component:抽象界面构件类,充当抽象构件类

(2) Window:窗体类,充当具体构件类

(3) TextBox:文本框类,充当具体构件类

(4) ListBox:列表框类,充当具体构件类

(5) ComponentDecorator:构件装饰类,充当抽象装饰类

(6) ScrollBarDecorator:滚动条装饰类,充当具体装饰类

(7) BlackBorderDecorator:黑色边框装饰类,充当具体装饰类

(8) Client:客户端测试类

结果及分析
1、实现多次装饰(代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package designpatterns.decorator;

public 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();
}
}
为构件增加黑色边框!
为构件增加滚动条!
显示窗体!

透明装饰模式

  1. 透明(Transparent)装饰模式:要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型

  2. 对于客户端而言,具体构件对象和具体装饰对象没有任何区别

  3. 可以让客户端透明地使用装饰之前的对象和装饰之后的对象,无须关心它们的区别

  4. 可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象

  5. 无法在客户端单独调用新增方法addedBehavior()

1
2
3
4
5
6
7
8
……
Component component_o,component_d1,component_d2; //全部使用抽象构件定义
component_o = new ConcreteComponent();
component_d1 = new ConcreteDecorator1(component_o);
component_d2 = new ConcreteDecorator2(component_d1);
component_d2.operation();
//无法单独调用component_d2的addedBehavior()方法
……

半透明装饰模式

  1. 半透明(Semi-transparent)装饰模式:用具体装饰类型来定义装饰之后的对象,而具体构件使用抽象构件类型来定义

  2. 对于客户端而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这是不透明的

  3. 可以给系统带来更多的灵活性,设计相对简单,使用起来也非常方便

  4. 客户端使用具体装饰类型来定义装饰后的对象,因此可以单独调用addedBehavior()方法

  5. 最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象

1
2
3
4
5
6
7
8
9
……
Component component_o; //使用抽象构件类型定义
component_o = new ConcreteComponent();
component_o.operation();
ConcreteDecorator component_d; //使用具体装饰类型定义
component_d = new ConcreteDecorator(component_o);
component_d.operation();
component_d.addedBehavior(); //单独调用新增业务方法
……

模式优点

  • 对于扩展一个对象的功能装饰模式比继承更加灵活,不会导致类的个数急剧增加

  • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为

  • 可以对一个对象进行多次装饰

  • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无须改变,符合开闭原则

模式缺点

  • 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能

  • 比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐

模式适用环境

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责

  • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式

课后思考

半透明装饰模式能否实现对同一个对象的多次装饰?为什么?

不能。原因见前面

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2023-2024 Guijie Wang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信