目录
1.装饰者模式定义
2.优点
3.缺点
5.工作流程
6.示例
7.代码练习
8.应用场景
9.本质
10.涉及的设计原则
11.相关的设计模式
12.开源框架中的应用
装饰者模式定义
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更为灵活。装饰者模式通过将对象包装在装饰器对象中来实现这一目标,从而形成一条装饰器链。
优点
- 允许动态地扩展对象的功能,避免了使用继承导致的类爆炸问题。
- 可以通过组合不同的装饰器来构建灵活的对象结构。
- 具体组件和装饰器都可以独立变化,符合单一职责原则。
缺点
- 可能导致装饰器链变得复杂,不易理解。
- 装饰器模式增加了许多小型对象,可能会导致性能损失。
装饰者模式结构说明
- Component(组件):定义了一个抽象接口,可以被具体组件和装饰器实现。这是装饰器模式中所有具体组件和装饰器的共同接口。
- ConcreteComponent(具体组件):实现了 Component 接口的具体组件类,是被装饰的对象,它可以被一个或多个装饰器包装。
- Decorator(装饰器):也实现了 Component 接口,但它通常包含一个对 Component 的引用,并且可以包装一个或多个其他装饰器或具体组件。
- ConcreteDecorator(具体装饰器):是装饰器模式中的具体装饰器类,它通过扩展装饰器类来添加额外的功能或行为。
工作流程
- 客户端通过 Component 接口与具体组件进行交互。
- 装饰器对象与具体组件实现相同的 Component 接口,这使得装饰器可以替代具体组件。
- 装饰器包装具体组件,可以添加额外的功能或行为。
- 客户端可以链式组合多个装饰器来构建复杂的对象结构。
示例
装饰最简单的示例莫过于服饰了,一件衬衫上可以装饰胸针、袖扣,也可以加上口袋。
代码练习
1.创建抽象接口Clothes,提供一个sale()方法。
// 抽象接口 - 衣服
public interface Clothes {
double sale();
}
2.创建装饰器Brooch、CuffLinks和Pocket,包含一个Clothes的引用
// 装饰器 - 胸针
public abstract class Brooch implements Clothes {
protected Clothes clothes;
}
// 装饰器 - 袖扣
public abstract class CuffLinks implements Clothes {
protected Clothes clothes;
}
// 装饰类 - 口袋
public abstract class Pocket implements Clothes {
protected Clothes clothes;
}
3.创建被装饰的对象Shirt
// 具体组件类(被装饰对象) - 衬衫
public class Shirt implements Clothes {
@Override
public double sale() {
return 50;
}
}
4.创建具体装饰器BearBrooch、MonkeyCuffLinks和SquarePocket.
// 具体装饰类 - 小熊胸针
public class BearBrooch extends Brooch {
public BearBrooch(Clothes clothes){
this.clothes = clothes;
}
@Override
public double sale() {
return clothes.sale() + 5;
}
}
// 具体装饰类 - 猴子袖扣
public class MonkeyCuffLinks extends CuffLinks {
public MonkeyCuffLinks(Clothes clothes){
this.clothes = clothes;
}
@Override
public double sale() {
return clothes.sale() + 10;
}
}
// 具体装饰类 —— 方形口袋
public class SquarePocket extends Pocket {
@Override
public double sale() {
return 0;
}
// 扩展功能
public void takeSundries(String sundries){
System.out.println("口袋里装了:" + sundries);
}
}
客户端对衬衫进行装饰,扩展功能和行为:
public class DecoratorClient {
public static void main(String[] args) {
// 这是一件衬衫
Clothes clothes = new Shirt();
System.out.println("衬衫售价:" + clothes.sale());
// 佩戴一枚小熊胸针
clothes = new BearBrooch(clothes);
System.out.println("小熊胸针衬衫售价:" + clothes.sale());
// 佩戴猴子袖扣
clothes = new MonkeyCuffLinks(clothes);
System.out.println("猴子袖扣衬衫售价:" + clothes.sale());
// 有口袋的衬衫
clothes = new SquarePocket(clothes);
// 口袋装了只笔
((SquarePocket) clothes).takeSundries("pen");
System.out.printf("口袋衬衫的售价:" + clothes.sale());
}
}
应用场景
- 当需要在不修改现有代码的情况下动态地添加功能或行为时。
- 当一个对象需要在运行时动态地添加或删除功能。
- 当需要通过多个小型、独立的装饰器来构建复杂的对象。
本质
动态地为对象添加功能。同时被装饰对象不感知这些功能的存在。这种方式允许在不修改现有代码的情况下扩展对象的行为,同时保持对象的单一职责原则。
涉及的设计原则
- 开闭原则:可以在不修改现有代码的情况下扩展对象的功能。
- 单一职责原则:每个类应该只有一个修改的理由,装饰器模式将功能的添加和具体组件的实现分开。
相关的设计模式
- 装饰者模式通常与适配器模式和工厂模式结合使用,以便创建和包装对象。
开源框架中的应用
在Java中,I/O流的处理就是一个经典的装饰者模式的例子。例如,BufferedReader 和 BufferedWriter 都是装饰器,它们可以包装基本的 Reader 和 Writer,并添加缓冲功能,提高I/O性能。客户端可以根据需要链式组合多个装饰器来构建不同的I/O流。