【设计模式】装饰者模式

装饰者模式是一种设计模式,用于在运行时动态地给对象添加额外的责任。通过装饰者,我们可以不修改原有代码的情况下,扩展对象功能。在例子中,奶茶是被装饰者,小料如布丁和珍珠是装饰者,它们通过装饰增加了奶茶的种类和价格。这种模式提供了比继承更具弹性的扩展选项,但过度使用可能导致对象数量过多,增加复杂性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰者模式

装饰者模式的基本概念在生活中到时都是体现。比如装修房子,房子就是被装饰者,各种装修材料就是装饰者;我们每天都会打扮自己,我们自己就是一个被装饰者,各种衣服、饰品、化妆品就是装饰者;还有就是大家喜欢喝的奶茶,每一种奶茶就是被装饰者,加的小料就是装饰者。

装饰者模式的定义
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更具有弹性的替代方案。

是一个符合开放-关闭原则的模式。

标准类图
在这里插入图片描述
Component:组件超类(也可以是一个接口),具体的组件(被装饰者)类和装饰者都继承它,保证为一致的类型。
ConcreteComponent:具体的组件(被装饰者)类。
Decorator:装饰者的基类,继承组件超类,每个装饰者都会包装一个组件,有一个变量保存这个包装的组件。
ConcreteDecorator:具体的装饰者,一个变量用来记录装饰者装饰的组件,也可扩展Component的状态。

几个注意的要点:

  • 装饰者与被装饰者是具有相同的超类的。
  • 可以用一个或多个装饰者包装一个对象。包装的方式是通过装饰者的构造方法传入被装饰的对象,得到一个被包装过的对象,由于装饰者与被装饰者是具有相同的超类的,所以这个被包装过的对象仍然能继续被包装。
  • 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为。
  • 对象可以在任何时候被修饰,所以可以在运行时动态地,不限量地用你喜欢的装饰者来修饰。

实例

下面我们举一个实际的例子,通过代码来进一步理解装饰者模式的用途。

实际场景
当我们去奶茶店买奶茶时候,首先会选择奶茶品种,然后再向里面加小料,最后店员会用点餐机器打印出来结果,上面会有奶茶种类和小料,还会有总共的价格,那么在装饰者模式中又是怎样实现的呢?在装饰者模式中,不同品种的奶茶就是组件(被装饰者),小料就是装饰者,我们会通过小料来装饰奶茶,最后得到结果。

代码实现
MilkTea.java 组件超类

//奶茶,组件超类
public abstract class MilkTea {
    //一个描述当前奶茶种类或小料种类的字符串
    String description="MilkTea";
    //返回种类的方法
    public String getDescription(){
        return description;
    }
    //一个返回当前物品价钱的抽象方法
    public abstract double cost();
}

SmallMaterial.java 装饰者基类

//小料,装饰者基类继承组件超类
public abstract class SmallMaterial extends MilkTea{
    //小料种类名称的返回方法
    public abstract String getDescription();
   
}

Oreo.java 具体的组件(被装饰者)类

//奥利奥奶茶,具体的组件类
public class Oreo extends MilkTea{

    //通过构造方法,传入具体奶茶的种类
    public Oreo(){
        description="Oreo";
    }

    @Override
    public double cost() {
        return 15;
    }
}

Padding.java 具体的装饰者类

//布丁,装饰者的具体类
public class Padding extends SmallMaterial{

    MilkTea milkTea; //用一个实例变量来记录被装饰的奶茶

    //通过布丁的构造方法,设定它所装饰哪种奶茶
    public Padding(MilkTea milkTea){
        this.milkTea=milkTea;
    }

    //返回布丁和所装饰奶茶的总价钱
    @Override
    public double cost() {
        return 2+milkTea.cost();
    }

    //返回所装饰奶茶的名称和布丁的名称
    @Override
    public String getDescription() {
        return milkTea.getDescription()+"+padding";
    }
}

Pearl.java 具体的装饰者类

//珍珠,装饰者的具体类
public class Pearl extends SmallMaterial{
    MilkTea milkTea; //用一个实例变量来记录被装饰的奶茶

    //通过珍珠的构造方法,设定它所装饰哪种奶茶
    public Pearl(MilkTea milkTea){
        this.milkTea=milkTea;
    }

    //返回珍珠和所装饰奶茶的总价钱
    @Override
    public double cost() {
        return 1.5+milkTea.cost();
    }

    //返回所装饰奶茶的名称和珍珠的名称
    @Override
    public String getDescription() {
        return milkTea.getDescription()+"+pearl";
    }
}

使用装饰者装饰组件

public static void main(String[] args) {
    MilkTea milkTea=new Oreo(); //创建一个奥利奥奶茶实例,待包装的被装饰者
    milkTea=new Padding(milkTea); //使用布丁的构造方法装饰奥利奥奶茶,返回一个包装过的对象
    milkTea=new Pearl(milkTea); //使用珍珠的构造方法继续装饰被包装过
    
    //输出被装饰过对象的物品和价格信息
    System.out.println(milkTea.getDescription()+"  price="+milkTea.cost());
}

整个装饰过程是这样的
在这里插入图片描述

测试结果

显示了该被装饰者和所有装饰者的名称,总共的价钱
在这里插入图片描述
缺点:如果过度使用,会导致出现许多的对象,这会让程序变得很复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值