装饰器模式 详解 设计模式

装饰器模式

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

结构:

  • 抽象组件(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类)
相关推荐
追风林5 分钟前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨20 分钟前
El表达式和JSTL
java·el
q5673152320 分钟前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
也无晴也无风雨1 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
duration~1 小时前
Maven随笔
java·maven
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
密码小丑1 小时前
11月4日(内网横向移动(一))
笔记