设计模式大白话之装饰者模式

想象一下,你走进一家咖啡馆,点了一杯美式咖啡。但是,你可能还想根据自己的口味添加一些东西,比如奶泡、巧克力粉、焦糖酱或是肉桂粉。每次你添加一种配料,你的咖啡就会变得更丰富,同时价格也会相应增加。

在软件设计中,装饰者模式就是让你能够在不改变原始对象的情况下,动态地给它添加新功能或增强现有功能。这就好比你在咖啡上加配料,不是通过制作一种全新的咖啡,而是通过在现有的基础上增加东西。

比如,假设你正在开发一个文本编辑器,你希望用户可以选择开启一些额外的功能,比如语法高亮、行号显示、自动完成等。你不想为每一种可能的组合都创建一个单独的文本编辑器类,因为那样会有无数种组合,维护起来会非常困难。

这时,装饰者模式就派上用场了。你可以创建一个基本的文本编辑器类,然后为每一个额外功能创建一个装饰者类。当用户选择开启某项功能时,你就在基本的文本编辑器上“装饰”上相应的装饰者。这样,用户就可以根据自己的需求,动态地定制他们自己的文本编辑器,而不需要重新编写整个程序。

简而言之,装饰者模式就像是给你的软件产品添加“配料”,让它变得更有个性,更符合用户的需求,而无需更改其核心结构。

 以一家奶茶店为例,使用装饰者模式来动态地给奶茶添加各种配料。我们将创建一个基础的奶茶类,然后使用装饰者类来添加不同的配料,如珍珠、布丁、红豆、仙草、芝士等。

首先,我们定义奶茶的基本接口:
public abstract class Drink {
    // 基本属性
    protected String description = "Unknown Drink";

    // 获取描述
    public String getDescription() {
        return description;
    }

    // 设置描述
    public void setDescription(String description) {
        this.description = description;
    }

    // 抽象方法,计算价格
    public abstract double cost();
}
接下来,我们创建基础的奶茶类:
public class MilkTea extends Drink {
    public MilkTea() {
        description = "Milk Tea";
    }

    public double cost() {
        return 3.5; // 假设一杯基础奶茶的价格是3.5元
    }
}
然后,我们定义装饰者基类:
public abstract class AddOns extends Drink {
    protected Drink drink;

    public AddOns(Drink drink) {
        this.drink = drink;
    }

    public String getDescription() {
        return drink.getDescription();
    }

    public double cost() {
        return drink.cost();
    }
}
接着,我们创建具体的配料装饰者:
public class Boba extends AddOns {
    public Boba(Drink drink) {
        super(drink);
    }

    @Override
    public String getDescription() {
        // 返回被装饰对象的描述
        return super.getDescription()+",  with Boba";
    }

    @Override
    public double cost() {
        return drink.cost() + 1.0; // 添加珍珠的成本
    }
}
public class Pudding extends AddOns {
    public Pudding(Drink drink) {
        super(drink);
        
    }

    @Override
    public String getDescription() {
        // 返回被装饰对象的描述
        return super.getDescription()+", with Pudding";
    }

    @Override
    public double cost() {
        return drink.cost() + 0.8; // 添加布丁的成本
    }
}
public class RedBeans extends AddOns {
    public RedBeans(Drink drink) {
        super(drink);
    }

    @Override
    public String getDescription() {
        // 返回被装饰对象的描述
        return super.getDescription()+",  with Red Beans";
    }

    @Override
    public double cost() {
        return drink.cost() + 0.7; // 添加红豆的成本
    }
}
最后,在主函数中使用这些装饰者:
public class Main {
    public static void main(String[] args) {
        Drink milkTea = new MilkTea();
        System.out.println(milkTea.getDescription() + ": " + milkTea.cost());

        Drink milkTeaWithBoba = new Boba(milkTea);
        System.out.println(milkTeaWithBoba.getDescription() + ": " +  milkTeaWithBoba.cost());

        Drink milkTeaWithBobaAndPudding = new Pudding(milkTeaWithBoba);
        System.out.println(milkTeaWithBobaAndPudding.getDescription() + ": " + milkTeaWithBobaAndPudding.cost());

        Drink milkTeaWithBobaAndRedBeans = new RedBeans(milkTeaWithBoba);
        System.out.println(milkTeaWithBobaAndRedBeans.getDescription() + ": " + milkTeaWithBobaAndRedBeans.cost());
    }
}
执行结果
Milk Tea: 3.5
Milk Tea,  with Boba: 4.5
Milk Tea,  with Boba, with Pudding: 5.3
Milk Tea,  with Boba,  with Red Beans: 5.2

在上述代码中,Drink 是奶茶及其配料的抽象基类,MilkTea 是基本的奶茶实现,AddOns 是所有配料的基类,而Boba, Pudding, RedBeans 分别是具体的配料装饰者。通过组合不同的装饰者,我们可以轻松地构建出各种不同配料组合的奶茶,而且这些组合是在运行时动态决定的。

理解这种思想然后之后就是如何熟练运用,在有需要的时候。

相关推荐

  1. 设计模式大白话装饰模式

    2024-07-18 05:24:02       20 阅读
  2. 设计模式装饰模式

    2024-07-18 05:24:02       52 阅读
  3. 设计模式装饰模式

    2024-07-18 05:24:02       55 阅读
  4. 大话设计模式装饰模式

    2024-07-18 05:24:02       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 05:24:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 05:24:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 05:24:02       58 阅读
  4. Python语言-面向对象

    2024-07-18 05:24:02       69 阅读

热门阅读

  1. 8个步骤彻底清理Docker镜像

    2024-07-18 05:24:02       28 阅读
  2. C#调用非托管dll,并从dll中再调用C#中的方法

    2024-07-18 05:24:02       23 阅读
  3. tomcat日志与log4j日志保留最近7天

    2024-07-18 05:24:02       23 阅读
  4. 一次超时导致的协程泄露

    2024-07-18 05:24:02       20 阅读
  5. day7 错误恢复(Panic Recover)

    2024-07-18 05:24:02       16 阅读
  6. c++邻接表

    2024-07-18 05:24:02       19 阅读
  7. Swift 数据类型

    2024-07-18 05:24:02       22 阅读
  8. 入门C语言只需一个星期(星期二)

    2024-07-18 05:24:02       22 阅读
  9. 国产大模型体验:DeepSeek、Kimi与智谱清言

    2024-07-18 05:24:02       20 阅读