装饰器模式 详解 设计模式

装饰器模式

它允许你在不改变对象结构的情况下,动态地将新功能附加到对象上。

结构:

  • 抽象组件(Component):定义了原始对象和装饰器对象的公共接口或抽象类,可以是具体组件类的父类或接口。
  • 具体组件(Concrete Component):是被装饰的原始对象,它定义了需要添加新功能的对象。
  • 抽象装饰器(Decorator):继承自抽象组件,它包含了一个抽象组件对象,并定义了与抽象组件相同的接口,同时可以通过组合方式持有其他装饰器对象。
  • 具体装饰器(Concrete Decorator):实现了抽象装饰器的接口,负责向抽象组件添加新的功能。具体装饰器通常会在调用原始对象的方法之前或之后执行自己的操作。

图例:

平常假如要加一个配料,都需要修改餐品的源代码,但是随着配料的增多, 类会变得越来越庞大,等下类爆炸了。

java 复制代码
public class Main {
    public static void main(String[] args) {
        FriedNoodles friedNoodles = new FriedNoodles();
        friedNoodles.addBacon();
        friedNoodles.addEgg();
        friedNoodles.addFish();

        System.out.println("Cost: $" + friedNoodles.getCost());
    }
}

案例:

假设有一个简单的咖啡店系统,其中有一个 Coffee 接口表示咖啡,它有一个方法 getCost() 来获取咖啡的价格。现在我们要给咖啡添加一些额外的配料,比如牛奶、摩卡和奶泡。

java 复制代码
// 咖啡接口
interface Coffee {
    double getCost();
}

// 具体咖啡类
class SimpleCoffee implements Coffee {
    @Override
    public double getCost() {
        return 1.0;
    }
}

// 装饰者抽象类
abstract class CoffeeDecorator implements Coffee {
    protected final Coffee decoratedCoffee;

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

    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

// 具体装饰者类
class Milk extends CoffeeDecorator {
    public Milk(Coffee decoratedCoffee) {
        super(decoratedCoffee);
    }

    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

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

    @Override
    public double getCost() {
        return super.getCost() + 1.0;
    }
}

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

    @Override
    public double getCost() {
        return super.getCost() + 0.3;
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        coffee = new Milk(coffee);
        coffee = new Mocha(coffee);
        coffee = new Foam(coffee);

        System.out.println("Cost: $" + coffee.getCost());
    }
}

通过组合不同的装饰者,可以在不改变原有咖啡对象的情况下,动态地添加额外的功能和费用。

使用场景:

  • 动态地给对象添加功能:当需要给对象动态地添加一些额外的功能,而且这些功能可以独立于该对象的创建。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类定义不能继承(如final类)
相关推荐
shuair41 分钟前
idea 2023.3.7常用插件
java·ide·intellij-idea
paterWang1 小时前
基于 Python 和 OpenCV 的酒店客房入侵检测系统设计与实现
开发语言·python·opencv
小安同学iter1 小时前
使用Maven将Web应用打包并部署到Tomcat服务器运行
java·tomcat·maven
Yvonne9781 小时前
创建三个节点
java·大数据
东方佑1 小时前
使用Python和OpenCV实现图像像素压缩与解压
开发语言·python·opencv
红花与香菇2____2 小时前
【学习笔记】Cadence电子设计全流程(二)原理图库的创建与设计(上)
笔记·嵌入式硬件·学习·pcb设计·cadence·pcb工艺
我真不会起名字啊2 小时前
“深入浅出”系列之杂谈篇:(3)Qt5和Qt6该学哪个?
开发语言·qt
laimaxgg2 小时前
Qt常用控件之单选按钮QRadioButton
开发语言·c++·qt·ui·qt5
水瓶丫头站住2 小时前
Qt的QStackedWidget样式设置
开发语言·qt
不会飞的小龙人2 小时前
Kafka消息服务之Java工具类
java·kafka·消息队列·mq