Java设计模式实战:装饰模式在星巴克咖啡系统中的应用

一、装饰模式简介

装饰模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

二、星巴克咖啡系统设计

根据提供的UML类图,我们来设计一个星巴克咖啡下单系统,该系统可以计算不同咖啡和调料组合的价格。

系统组成

  1. 抽象组件(Beverage):相当于Component类,是所有咖啡和调料的基类

  2. 具体组件:HouseBlend、Expresso、DarkRoast、Decaf,代表不同类型的咖啡

  3. 装饰器(CondimentDecorator):抽象装饰类

  4. 具体装饰器:Milk、Mocha、Soy、Whip,代表不同的调料

三、代码实现

1. 抽象组件(Beverage)

复制代码
/**
 * 抽象组件 - 饮料基类
 * 相当于装饰模式中的Component角色
 */
public abstract class Beverage {
    // 饮料描述,初始为"Unknown Beverage"
    String description = "Unknown Beverage";
    
    /**
     * 获取饮料描述
     * @return 饮料描述字符串
     */
    public String getDescription() {
        return description;
    }
    
    /**
     * 计算饮料价格 - 抽象方法,由子类实现
     * @return 饮料价格
     */
    public abstract double cost();
}

2. 具体组件(各种咖啡类型)

2.1 HouseBlend 咖啡

复制代码
/**
 * 具体组件 - 混合咖啡
 */
public class HouseBlend extends Beverage {
    public HouseBlend() {
        description = "House Blend Coffee";
    }
    
    @Override
    public double cost() {
        return 0.89;  // 基础价格0.89美元
    }
}

2.2 Expresso 咖啡

复制代码
/**
 * 具体组件 - 浓缩咖啡
 */
public class Expresso extends Beverage {
    public Expresso() {
        description = "Expresso";
    }
    
    @Override
    public double cost() {
        return 1.99;  // 基础价格1.99美元
    }
}

2.3 DarkRoast 咖啡

复制代码
/**
 * 具体组件 - 深焙咖啡
 */
public class DarkRoast extends Beverage {
    public DarkRoast() {
        description = "Dark Roast Coffee";
    }
    
    @Override
    public double cost() {
        return 0.99;  // 基础价格0.99美元
    }
}

2.4 Decaf 咖啡

复制代码
/**
 * 具体组件 - 低因咖啡
 */
public class Decaf extends Beverage {
    public Decaf() {
        description = "Decaf Coffee";
    }
    
    @Override
    public double cost() {
        return 1.05;  // 基础价格1.05美元
    }
}

3. 抽象装饰器(CondimentDecorator)

复制代码
/**
 * 抽象装饰器 - 调料装饰器基类
 * 继承自Beverage,所以装饰器可以嵌套装饰器
 */
public abstract class CondimentDecorator extends Beverage {
    /**
     * 获取完整描述 - 抽象方法
     * 每个具体装饰器需要实现如何添加自己的描述
     */
    @Override
    public abstract String getDescription();
}

4. 具体装饰器(各种调料)

4.1 Milk 牛奶

复制代码
/**
 * 具体装饰器 - 牛奶
 */
public class Milk extends CondimentDecorator {
    // 被装饰的饮料
    Beverage beverage;
    
    public Milk(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Milk";  // 添加牛奶描述
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.10;  // 增加0.10美元
    }
}

4.2 Mocha 摩卡

复制代码
/**
 * 具体装饰器 - 摩卡
 */
public class Mocha extends CondimentDecorator {
    Beverage beverage;
    
    public Mocha(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Mocha";  // 添加摩卡描述
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.20;  // 增加0.20美元
    }
}

4.3 Soy 豆浆

复制代码
/**
 * 具体装饰器 - 豆浆
 */
public class Soy extends CondimentDecorator {
    Beverage beverage;
    
    public Soy(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Soy";  // 添加豆浆描述
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.15;  // 增加0.15美元
    }
}

4.4 Whip 奶泡

复制代码
/**
 * 具体装饰器 - 奶泡
 */
public class Whip extends CondimentDecorator {
    Beverage beverage;
    
    public Whip(Beverage beverage) {
        this.beverage = beverage;
    }
    
    @Override
    public String getDescription() {
        return beverage.getDescription() + ", Whip";  // 添加奶泡描述
    }
    
    @Override
    public double cost() {
        return beverage.cost() + 0.10;  // 增加0.10美元
    }
}

5. 客户端使用示例

复制代码
/**
 * 星巴克咖啡店 - 客户端代码
 */
public class StarbuzzCoffee {
    public static void main(String args[]) {
        // 示例1:一杯纯Espresso
        Beverage beverage1 = new Expresso();
        System.out.println(beverage1.getDescription() + " $" + beverage1.cost());
        
        // 示例2:DarkRoast加双份Mocha和Whip
        Beverage beverage2 = new DarkRoast();
        beverage2 = new Mocha(beverage2);  // 第一次装饰:加Mocha
        beverage2 = new Mocha(beverage2);  // 第二次装饰:再加Mocha
        beverage2 = new Whip(beverage2);   // 第三次装饰:加Whip
        System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
        
        // 示例3:HouseBlend加Soy、Mocha和Whip
        Beverage beverage3 = new HouseBlend();
        beverage3 = new Soy(beverage3);   // 第一次装饰:加Soy
        beverage3 = new Mocha(beverage3);  // 第二次装饰:加Mocha
        beverage3 = new Whip(beverage3);   // 第三次装饰:加Whip
        System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
    }
}

四、代码结构说明

  1. Beverage 是所有饮料的基类,定义了基本接口

  2. 具体咖啡类型(HouseBlend、Expresso等)继承Beverage,实现具体价格

  3. CondimentDecorator是装饰器基类,也继承自Beverage

  4. 具体调料(Milk、Mocha等)继承CondimentDecorator,包装一个Beverage对象

  5. 客户端可以自由组合咖啡和调料,通过层层装饰实现复杂组合

五、装饰模式的优势

  1. 灵活性:可以动态地添加或删除功能,比继承更灵活

  2. 避免类爆炸:不需要为每种组合创建子类

  3. 符合开闭原则:对扩展开放,对修改关闭

  4. 运行时添加功能:可以在运行时决定添加哪些装饰

六、总结

通过这个星巴克咖啡系统的例子,我们看到了装饰模式在实际应用中的强大之处。它让我们能够轻松地组合各种咖啡和调料,而不需要创建大量的子类。这种模式特别适合那些需要动态、透明地添加对象功能的场景。

相关推荐
云和数据.ChenGuang几秒前
项目打开后没有主类
开发语言·人工智能·langchain·1024程序员节
范同学~1 分钟前
项目添加水印
java·前端·javascript
鬼手点金3 分钟前
缓存作为架构约束
开发语言·前端·人工智能·python·microsoft·缓存·架构
快乐的韭菜根根5 分钟前
Slurm 指定 GPU 卡:`File=/dev/nvidiaX` 映射的坑与修复
java·服务器·网络
SEO_juper8 分钟前
Node.js 页面主题聚焦度检测:title 和正文各说各的,AI 也读不懂
开发语言·人工智能·node.js·seo·外贸独立站
软件技术NINI12 分钟前
基于PHP和MySQL的快递代收点管理系统的设计与实现
开发语言·javascript·数据库·mysql·毕业设计·php·毕设
长不大的杨瑞杰17 分钟前
OpenCode v2 远程开发实战:Web UI、Pair、SSH 隧道与 OpenTunnel 安全接入
人工智能·安全·云计算·软件工程·devops
酣大智18 分钟前
hibernate学习笔记
java·hibernate·session
Dovis(誓平步青云)24 分钟前
一个分区超温就全棚浇水,控制系统怎样按区下策略
开发语言·前端·javascript·人工智能·机器学习
kiracrimson31 分钟前
编码简述:内存里没有文字,只有一张对照表
开发语言·c++·二进制·计算机组成原理