装饰者模式

本文通过咖啡店订单系统的实例,介绍了装饰者模式如何在运行时动态添加行为,保持接口一致,以及其优点和可能的缺点。
摘要由CSDN通过智能技术生成

装饰者模式是一种结构型设计模式,用于动态地给对象添加额外的行为或责任,而无需修改其原始类。这种模式允许你将对象包装在一个装饰者类中,并在运行时动态地添加新的行为,同时保持接口的一致性。下面我将通过一个简单的咖啡店订单系统的例子来说明装饰者模式。

背景介绍

假设你经营一家咖啡店,你的订单系统需要处理各种类型的咖啡饮品。每种咖啡饮品都有一个基本价格,但顾客可以选择在咖啡中添加额外的配料,如牛奶、糖浆或奶泡,每种配料都会额外收费。

实现思路

  1. 定义一个抽象的咖啡饮品接口 Coffee,其中包含计算价格和获取描述的方法。
  2. 创建具体的咖啡类 SimpleCoffee,实现 Coffee 接口,表示基本的咖啡饮品。
  3. 建立装饰者类 CoffeeDecorator,它也实现了 Coffee 接口,包含一个 Coffee 对象的引用,用于动态添加新的行为。
  4. 创建具体的装饰者类,如 MilkDecorator 和 SugarDecorator,用于给咖啡中添加牛奶和糖等配料。
  5. 在客户端代码中,通过组合不同的装饰者类,动态地构建不同种类的咖啡饮品。

具体实现

首先,我们有一个抽象的咖啡饮品接口 Coffee:

package blog.装饰者模式;

public interface Coffee {
    double cost(); // 计算价格
    String getDescription(); // 获取描述
}

然后,我们有一个具体的咖啡类 SimpleCoffee,它实现了 Coffee 接口:

package blog.装饰者模式;

public class SimpleCoffee implements Coffee {
    @Override
    public double cost() {
        return 1.0; // 基本价格
    }

    @Override
    public String getDescription() {
        return "Simple coffee"; // 基本描述
    }
}

接下来,我们创建装饰者类 CoffeeDecorator,它也实现了 Coffee 接口,并包含一个 Coffee 对象的引用,用于动态添加新的行为:

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;

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

    @Override
    public double cost() {
        return decoratedCoffee.cost();
    }

    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
}

现在,我们可以创建具体的装饰者类,比如 MilkDecorator,它用于给咖啡中添加牛奶:

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double cost() {
        return super.cost() + 0.5; // 牛奶价格
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Milk"; // 追加描述
    }
}

我们再创建一个具体的装饰者类,SugarDecorator,用于给咖啡加糖

public class SugarDecorator extends CoffeeDecorator{
    public SugarDecorator(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }
    @Override
    public double cost() {
        return super.cost() + 0.5; // 糖价格
    }

    @Override
    public String getDescription() {
        return super.getDescription() + ", Sugar"; // 追加描述
} 
}

使用装饰者模式,我们可以动态地给咖啡添加各种配料,而不需要修改原始的 Coffee 类。例如:

public class Main {
    public static void main(String[] args) {
        Coffee simpleCoffee = new SimpleCoffee();
        System.out.println("Cost: " + simpleCoffee.cost() + "; Description: " + simpleCoffee.getDescription());

        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        System.out.println("Cost: " + milkCoffee.cost() + "; Description: " + milkCoffee.getDescription());

        Coffee milkAndSugarCoffee = new SugarDecorator(milkCoffee);
        System.out.println("Cost: " + milkAndSugarCoffee.cost() + "; Description: " + milkAndSugarCoffee.getDescription());
    }
}

输出:
image.png

总结

装饰者模式是一种灵活的设计模式,它有许多优点和一些缺点。

优点:

动态性: 装饰者模式允许你在运行时动态地添加或删除对象的功能,而不需要修改其原始类,这使得系统更加灵活。
遵循开闭原则: 装饰者模式通过组合而不是继承来扩展对象的功能,因此遵循开闭原则,即对修改关闭,对扩展开放。
单一职责原则: 装饰者模式使得每个类只需要关注自己的核心功能,装饰者类负责附加功能,从而遵循了单一职责原则。
可复用性: 装饰者模式允许你独立地组合不同的装饰者类,这些装饰者可以被复用于不同的对象,增加了代码的可复用性。
保持对象接口一致性: 装饰者模式通过实现相同的接口来包装不同的对象,因此不会改变对象的外部行为,保持了对象接口的一致性。

缺点:

可能产生过多的小对象: 使用装饰者模式会导致系统中出现大量的小对象,如果过度使用装饰者模式,可能会导致对象数量过多,增加系统的复杂性。
理解和维护难度: 装饰者模式涉及到多层嵌套的装饰者类,可能会增加代码的理解和维护难度,特别是对于复杂的装饰者组合结构。
不适用于所有情况: 装饰者模式适用于需要动态地给对象添加功能的场景,但并不适用于所有情况,有时候使用其他设计模式如策略模式或状态模式可能更合适。
尽管装饰者模式存在一些缺点,但在需要动态地扩展对象功能而又不想修改原始类的情况下,它仍然是一个强大且灵活的设计模式。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值