装饰器模式 详解 设计模式

装饰器模式

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

结构:

  • 抽象组件(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类)
相关推荐
tang7778934 分钟前
爬虫如何绕过绕过“5秒盾”Cloudflare:从浏览器指纹模拟到Rust求解之不完全指南
开发语言·爬虫·rust·cloudflare
Yuer202537 分钟前
什么是 Rust 语境下的“量化算子”——一个工程对象的最小定义
开发语言·后端·rust·edca os·可控ai
hqwest40 分钟前
码上通QT实战26--系统设置01-系统设置布局
开发语言·qt·qss·qt基础控件·qt布局控件·qt表格控件
薛定谔的猫198242 分钟前
llama-index Embedding 落地到 RAG 系统
开发语言·人工智能·python·llama-index
记得开心一点嘛1 小时前
Redis封装类
java·redis
短剑重铸之日1 小时前
《7天学会Redis》Day 5 - Redis Cluster集群架构
数据库·redis·后端·缓存·架构·cluster
lkbhua莱克瓦241 小时前
进阶-存储过程3-存储函数
java·数据库·sql·mysql·数据库优化·视图
计算机程序设计小李同学1 小时前
基于SSM框架的动画制作及分享网站设计
java·前端·后端·学习·ssm
深情的小陈同学1 小时前
工作学习笔记 —— 支持手机端的添加表单行操作
笔记·学习·ai编程
鱼跃鹰飞1 小时前
JMM 三大特性(原子性 / 可见性 / 有序性)面试精简版
java·jvm·面试