您现在的位置是:首页 >学无止境 >设计模式-装饰器模式网站首页学无止境

设计模式-装饰器模式

码农界的菜鸟 2023-06-18 16:00:02
简介设计模式-装饰器模式

装饰器模式



什么是装饰器模式

  装饰器(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。


为什么使用装饰器模式

使用装饰者模式有如下好处:
  1. 避免了类爆炸问题,简化了设计
  2. 易于扩展,可以灵活组合不同调料
  3. 装饰类和被装饰类可以独立变化,没有严格耦合
  4. 符合开闭原则,扩展开放(可以添加更多调料),修改关闭(原有类不需要修改)
我们举个例子来说明,假设我们要开发一个咖啡店点餐系统。我们有以下对象:

  • Coffee:咖啡类,价格5元
  • Milk:牛奶类,价格1元
  • ChocolateChip:巧克力豆类,价格2元
  • WhipCream:奶油类,价格2元

如果不使用装饰者模式,我们可以这样设计:

// 咖啡类
public class Coffee {
    private String description = "咖啡";
    private double price = 5;
}

// 牛奶咖啡
public class CoffeeWithMilk extends Coffee {
    public CoffeeWithMilk() {
        description += " + 牛奶";
        price += 1; 
    }
}

// 巧克力豆咖啡
public class CoffeeWithChocolateChip extends Coffee {
   // ...
} 

// 奶油咖啡
public class CoffeeWithWhipCream extends Coffee {
   // ... 
}

// 巧克力豆牛奶咖啡
public class CoffeeWithMilkAndChocolateChip extends CoffeeWithMilk {
   // ...    
} 

但是这种设计有几个缺点:

  1. 会产生很多子类,导致过度继承,设计变得复杂
  2. 如果想添加更多的调料组合,子类数量会急剧增加,不易于维护
  3. Coffee 类和子类是耦合的,一旦 Coffee 类变化,子类也需要变化

使用装饰者模式可以这样设计:

java
public interface Coffee {  
    public double getPrice(); 
}

public class SimpleCoffee implements Coffee {
    @Override
    public double getPrice() {
        return 5; 
    }
}

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public double getPrice() {
        return coffee.getPrice();
    }
}

public class Milk extends CoffeeDecorator {
    public Milk(Coffee coffee) {
        super(coffee); 
    }

    @Override
    public double getPrice() {
        return super.getPrice() + 1; 
    }
}

// 其他调料装饰类(ChocolateChip,WhipCream)定义类似...

Coffee c = new SimpleCoffee();
c = new Milk(c); // 牛奶
c = new ChocolateChip(c);// 牛奶巧克力豆
c = new WhipCream(c);// 牛奶巧克力豆

System.out.println(c.getPrice()); // 9


如何使用装饰器模式

从上面的代码中,我们可以看出,装饰器模式主要包含以下角色。

  1、抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  2、具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  3、抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4、具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

在这里插入图片描述
上面的代码示例中,我们将各个类进行下划分:

  • Coffee 接口属于抽象构件
  • SimpleCoffee 类属于具体构件
  • CoffeeDecorator 抽象类属于抽象装饰
  • Milk、ChocolateChip 等类属于具体装饰

总结

  装饰器模式不是简单的“用组合替代继承”,装饰器模式相对于简单的组合关系,还有两个比较特殊的地方。

  • 装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。
  • 装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。