• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
思想人生从关注生活开始
博客园    首页    新随笔    联系   管理    订阅  订阅

装饰器模式Decorator Pattern-23种常用设计模式快速入门教程

1.装饰器模式定义

装饰器模式(Decorator Pattern)是一种结构型设计模式,它可以在不改变原有对象的基础上,动态地给对象添加新的职责和行为。 该模式的核心思想是以递归的方式,通过将对象包装在装饰器对象中,来不断添加新的行为和职责。装饰器模式的结构包括以下角色:

  • Component(抽象构件):定义一个抽象接口,用于表示被装饰对象的基本行为。
  • ConcreteComponent(具体构件):实现抽象构件接口,定义一个具体的对象,是被装饰的对象。
  • Decorator(抽象装饰器):维护一个指向抽象构件的引用,并定义一个与Component接口一致的接口,用于扩展Component的职责。
  • ConcreteDecorator(具体装饰器):实现抽象装饰器接口,扩展Component的职责,并维护一个指向Component的引用。 

2.装饰器模式优点

  • 可以动态地扩展对象的职责和行为,避免使用继承带来的静态扩展限制。在使用继承时,子类的职责和行为是在编译时确定的,而装饰器模式可以在运行时动态地添加新的职责和行为。这使得装饰器模式具有更强的灵活性,可以根据需要进行动态组合和扩展。
  • 可以组合多个装饰器对象,实现复杂的功能扩展。在装饰器模式中,可以通过组合多个装饰器对象来实现不同的职责和行为扩展。这使得装饰器模式可以应对复杂的功能扩展需求,同时也使得代码更加清晰和易于维护。
  • 装饰器模式符合“开闭原则”,可以在不改变原有代码的情况下,添加新的职责和行为。在装饰器模式中,可以通过添加新的装饰器类来扩展对象的职责和行为,而不需要修改原有代码。这使得装饰器模式具有很好的扩展性和维护性。

3.装饰器模式缺点

  • 装饰器模式会增加系统的复杂度和开销,因为需要创建多个装饰器对象。在使用装饰器模式时,可能需要创建多个装饰器对象来实现不同的职责和行为扩展。这会增加系统的复杂度和开销,同时也会降低系统的性能。
  • 装饰器模式容易造成设计上的混乱,因为不同的装饰器对象可能会有相互依赖关系。在使用装饰器模式时,可能会出现不同的装饰器对象之间存在相互依赖关系的情况,这会增加系统的复杂度和不稳定性。
  • 装饰器模式的嵌套层次过多可能会影响系统的性能。在使用装饰器模式时,可能会出现装饰器对象的嵌套层次过多的情况,这会增加系统的复杂度和降低系统的性能。因此,在使用装饰器模式时需要注意控制装饰器对象的嵌套层次。

4.装饰器设计模式示例代码

传统设计模式讲解时使用的示例代码,大都采用与读者日常生活接解的业务系统没有多大关联关系。以致大部分读者无法做到学以致用,学完就忘记。本文采用使用日常生活中随处可见的电商相关业务来编写实现代码

假设我们有一个电商平台,需要对商品进行价格计算,同时还需要对价格进行打折和折扣券的处理,我们可以使用装饰器模式来实现该功能。

首先定义一个抽象构件Component,表示商品的基本行为:

public interface Component {
double getPrice();
}

然后定义具体构件ConcreteComponent,表示一个具体的商品对象:

public class ConcreteComponent implements Component {
private double price;
public ConcreteComponent(double price) {
this.price = price;
}
@Override
public double getPrice() {
return price;
}
}

接着定义抽象装饰器Decorator,用于扩展Component的职责:

public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override public double getPrice() {
return component.getPrice();
}
}

最后定义具体装饰器ConcreteDecorator,实现抽象装饰器接口,扩展Component的职责,并维护一个指向Component的引用。

例如,我们可以定义一个DiscountDecorator,用于对商品价格进行打折处理:

public class DiscountDecorator extends Decorator {
private double discount;
public DiscountDecorator(Component component, double discount) {
super(component); this.discount = discount;
}
@Override
public double getPrice() {
return component.getPrice() * discount;
}
}

我们还可以定义一个CouponDecorator,用于对商品价格进行折扣券处理:

public class CouponDecorator extends Decorator {
private double coupon;
public CouponDecorator(Component component, double coupon) {
super(component);
this.coupon = coupon;
}
@Override
public double getPrice() {
return component.getPrice() - coupon;
}
}

这样,我们就可以通过组合不同的装饰器对象,对商品的价格进行灵活的计算和处理:

Component product = new ConcreteComponent(100.0);
// 打八折
 
product = new DiscountDecorator(product, 0.8);
// 减10元
product = new CouponDecorator(product, 10.0);
// 计算最终价格
double price = product.getPrice();
 
 

下面展示了如何通过嵌套多个装饰器对象来实现复杂的功能:


interface Component {
void operation();
}

class ConcreteComponent implements Component {
public void operation() {
System.out.println("ConcreteComponent operation");
}
}

abstract class Decorator implements Component {
protected Component component;

public Decorator(Component component) {
this.component = component;
}

public void operation() {
component.operation();
}
}

class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}

public void operation() {
super.operation();
addBehaviorA();
}

private void addBehaviorA() {
System.out.println("add Behavior A");
}
}

class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}

public void operation() {
super.operation();
addBehaviorB();
}

private void addBehaviorB() {
System.out.println("add Behavior B");
}
}

class ConcreteDecoratorC extends Decorator {
public ConcreteDecoratorC(Component component) {
super(component);
}

public void operation() {
super.operation();
addBehaviorC();
}

private void addBehaviorC() {
System.out.println("add Behavior C");
}
}

public class DecoratorDemo {
public static void main(String[] args) {
Component component = new ConcreteComponent();
Component decoratorA = new ConcreteDecoratorA(component);
Component decoratorB = new ConcreteDecoratorB(decoratorA);
Component decoratorC = new ConcreteDecoratorC(decoratorB);
decoratorC.operation();
}
}
```

在这个示例中,我们定义了一个抽象组件类 `Component` 和一个具体组件类 `ConcreteComponent` ,还定义了三个具体装饰器类 `ConcreteDecoratorA`、`ConcreteDecoratorB` 和 `ConcreteDecoratorC`。它们都继承自 `Decorator` 类,并通过嵌套其他装饰器对象来增加自己的职责。

在 `main()` 方法中,我们首先创建了一个具体组件对象 `ConcreteComponent` ,然后依次创建了三个装饰器对象 `ConcreteDecoratorA`、`ConcreteDecoratorB` 和 `ConcreteDecoratorC`,并将它们嵌套在一起使用。最后调用 `decoratorC.operation()` 方法输出结果,并观察其中添加了哪些行为。

这个示例展示了如何使用装饰器模式动态地为组件对象添加职责,并通过嵌套多个装饰器对象来实现复杂的功能。由于每个装饰器对象和被装饰对象具有相同的接口,因此可以方便地组合多个装饰器对象,并使得整个系统变得更加灵活。

为什么被装饰对象和装饰对象具有相同的接口 ?

在装饰器模式中,被装饰对象和装饰对象具有相同的接口,是因为这样做可以保证代码的灵活性和可扩展性。

首先,在面向对象编程中,接口是一种非常基础的概念,它提供了一个抽象层次,定义了一个类或者对象应该具有的属性和方法。通过将被装饰对象和装饰对象都实现同一个接口,我们可以保证它们可以互相替换,而且客户端不需要知道具体使用的是哪个对象。

其次,被装饰对象和装饰对象具有相同的接口可以让我们方便地组合多个装饰器,从而实现更加复杂的功能。装饰器模式允许我们动态地添加或删除对象的职责,每个装饰对象都可以通过嵌套其他装饰器来增加自己的职责,同时还能够保持相同的接口,使得整个系统变得更加灵活。

最后,在实际开发过程中,通常会出现一些基于框架或者基于接口的设计方式,这种设计方式可以使得程序实现更加灵活、易于维护和修改。因此,使用相同的接口可以促进代码的复用和替换,也可以使得代码更加具有可读性和可维护性。

综上所述,被装饰对象和装饰对象具有相同的接口是为了保证代码的灵活性和可扩展性,并且方便地组合多个装饰器来实现更加复杂的功能。

 

 

posted @ 2023-03-07 12:47  JackYang  阅读(148)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3