装饰模式的理解和实践

        在软件设计中,设计模式提供了一种可复用的解决方案,用于解决常见的设计问题。装饰模式(Decorator Pattern),也称为包装模式(Wrapper Pattern),是结构型设计模式之一。它通过一种对客户端透明的方式来动态地扩展对象的功能,能够在不修改原有对象结构的情况下,给对象添加新的职责。本文将从理解装饰模式的基本概念、工作原理、优缺点入手,再通过具体的Java代码示例来展示其在实际编程中的应用。

一、装饰模式的基本概念

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

  2. 核心思想:通过组合而非继承的方式,动态地给一个对象添加一些额外的职责。

  3. 结构:装饰模式包含以下几个角色:

    • Component:抽象构件,它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象。
    • ConcreteComponent:具体构件,它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法。装饰器可以给它增加额外的职责。
    • Decorator:抽象装饰类,它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前的构件对象的方法,但可以在调用这些方法之前或之后增加一些附加的行为。
    • ConcreteDecorator:具体装饰类,它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都只能增加一种职责,这样可以通过多个具体装饰类的链式调用,将多种职责组合在一起。

二、装饰模式的工作原理

        装饰模式的工作原理是通过组合的方式,将对象的功能进行扩展。它允许我们向一个现有的对象添加新的功能,同时又不改变其结构。装饰模式通过将对象放入包含行为的特殊封装对象中来实现。

  1. 透明装饰模式:客户端可以毫无差别地使用抽象构件接口和具体装饰对象。
  2. 半透明装饰模式:装饰类只装饰某些方法,而不是装饰所有方法。

三、装饰模式的优缺点

优点

  1. 扩展性:装饰模式提供了比继承更灵活的扩展性。通过组合的方式,可以在运行时动态地给对象添加职责,而不是在编译时静态地定义。
  2. 灵活性:通过不同的装饰类组合,可以创建出不同的行为组合。
  3. 复用性:装饰模式能够复用现有的代码,而不需要修改原有类的结构。

缺点

  1. 复杂性:使用装饰模式会导致类的数量增加,因为每个装饰类都需要实现接口或继承抽象类。
  2. 性能开销:由于装饰模式的对象实例在运行时创建,可能会有一定的性能开销。

四、装饰模式的实践

        下面我们通过Java代码来演示装饰模式的具体应用。假设我们有一个简单的咖啡订单系统,可以根据客户需求对咖啡进行不同的装饰,如加糖、加奶、加巧克力等。

1. 定义抽象构件接口

// 抽象构件接口
public interface Coffee {
    String getDescription();
    double getCost();
}

2. 定义具体构件类

// 具体构件类:简单的咖啡
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Simple Coffee";
    }

    @Override
    public double getCost() {
        return 2.0;
    }
}

3. 定义抽象装饰类

// 抽象装饰类
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;

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

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

    @Override
    public double getCost() {
        return coffee.getCost();
    }
}

4. 定义具体装饰类

// 具体装饰类:加糖
public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Sugar";
    }

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

// 具体装饰类:加奶
public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Milk";
    }

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

// 具体装饰类:加巧克力
public class ChocolateDecorator extends CoffeeDecorator {
    public ChocolateDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public String getDescription() {
        return coffee.getDescription() + ", Chocolate";
    }

    @Override
    public double getCost() {
        return coffee.getCost() + 1.5;
    }
}

5. 客户端代码

public class Client {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println("Coffee: " + coffee.getDescription() + ", Cost: $" + coffee.getCost());

        // 装饰咖啡:加糖
        Coffee decoratedCoffee = new SugarDecorator(coffee);
        System.out.println("Decorated Coffee: " + decoratedCoffee.getDescription() + ", Cost: $" + decoratedCoffee.getCost());

        // 装饰咖啡:加奶
        decoratedCoffee = new MilkDecorator(decoratedCoffee);
        System.out.println("Decorated Coffee: " + decoratedCoffee.getDescription() + ", Cost: $" + decoratedCoffee.getCost());

        // 装饰咖啡:加巧克力
        decoratedCoffee = new ChocolateDecorator(decoratedCoffee);
        System.out.println("Decorated Coffee: " + decoratedCoffee.getDescription() + ", Cost: $" + decoratedCoffee.getCost());
    }
}

运行结果

Coffee: Simple Coffee, Cost: $2.0
Decorated Coffee: Simple Coffee, Sugar, Cost: $2.5
Decorated Coffee: Simple Coffee, Sugar, Milk, Cost: $3.5
Decorated Coffee: Simple Coffee, Sugar, Milk, Chocolate, Cost: $5.0

总结

        装饰模式是一种非常灵活的设计模式,它通过组合的方式动态地扩展对象的功能。装饰模式允许我们向一个现有的对象添加新的职责,同时又不改变其结构。它提供了比继承更灵活的扩展性,使得我们可以在运行时动态地改变对象的行为。然而,使用装饰模式也可能会导致类的数量增加,以及一定的性能开销。因此,在实际应用中,我们需要根据具体的需求和场景来选择合适的设计模式。

        通过上面的Java代码示例,我们可以看到装饰模式在咖啡订单系统中的应用,通过不同的装饰类组合,可以创建出不同的咖啡类型和价格。这种设计模式在实际开发中非常有用,尤其是在需要动态扩展对象功能时。希望这篇文章能帮助你更好地理解和实践装饰模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/935207.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

游戏引擎学习第43天

仓库 https://gitee.com/mrxiao_com/2d_game 介绍运动方程 今天我们将更进一步,探索运动方程,了解真实世界中的物理,并调整它们,以创建一种让玩家感觉愉悦的控制体验。这并不是在做一个完美的物理模拟,而是找到最有趣…

Maven(生命周期、POM、模块化、聚合、依赖管理)详解

Maven构建项目的生命周期 在Maven出现之前,项目构建的生命周期就已经存在,软件开发人员每天都在对项目进行清理,编译,测试,部署等工作,这个过程就是项目构建的生命周期。虽然大家都在不停的做构建工作&…

第六届地博会开幕,世界酒中国菜美食文化节同期启幕推动地标发展

第六届知交会暨地博会开幕,辽黔欧三地馆亮点纷呈,世界酒中国菜助力地理标志产品发展 第六届知交会暨地博会盛大开幕,多地展馆亮点频出,美食文化节同期启幕推动地标产业发展 12月9日,第六届粤港澳大湾区知识产权交易博…

通过“思维链”提升ChatGPT提示词质量,更好的辅助学术论文

目录 1.写在开头 2.思维链是啥 1.写在开头 对于初步接触AIGC工具的宝子们,可以直接用最符合你习惯的方式去使用Kimi、ChatGPT这类AI工具。想到什么问题就问什么。对于比较简单直接的问题,不需要去想怎么写好提示词,直接在聊天窗口里表述你…

nacos bootstrap.yml 和 spring.config.import 加载配置的流程区别

相关依赖 springboot:2.7.15 nacos:2.2.3 bootstrap.yml加载方式 加载流程如下图所示 从图中可以看出,: 1.bootstrap.yml 的加载是在 BootstrapApplicationListener.onApplicationEvent 接收到 ApplicationEnvironmentPreparedEventEvent 事件后另起一个 Sprin…

高效项目托管指南:从本地到 GitHub 的完整流程

在现代软件开发中,将项目托管在 GitHub 上是一个常见且高效的方式。GitHub 不仅可以用作版本控制工具,还能帮助你与团队协作或展示自己的项目。本文将带你一步步完成项目的打包和上传。 高效项目托管指南:从本地到 GitHub 的完整流程 1. 准备…

【漏洞复现】CVE-2024-34102 Magento Open Source XXE漏洞

目录 漏洞介绍 影响版本 环境搭建 查看版本 漏洞复现 手动复现 漏洞 poc Magento Open Source 是一个免费开源的电子商务平台,适合中小企业或开发团队通过自定义代码和插件创建在线商店。它由社区开发和支持,功能强大但需要更多的技术投入。Adobe…

Scala的隐式对象

Scala中,隐式对象(implicit object)是一种特殊的对象,它可以使得其成员(如方法和值)在特定的上下文中自动可用,而无需显式地传递它们。隐式对象通常与隐式参数和隐式转换一起使用,以…

C# 委托详解02(委托和事件单独开一篇)

上一篇仅仅简单通过代码,以及相关运行示例,对委托有了基本概念。这一篇侧重对委托的更加深入的理解。有问题欢迎评论。本人技术不高,也欢迎指正。 希望看完我能够解释清楚以下问题,而大家能够从中找到自己的答案。 什么是委托&a…

【零成本抽象】基本概念与在C++中的实现

零成本抽象概念是由 Bjarne Stroustrup 提出的,他在 1994 年的著作中就有相关设想,2016 年其在 C++ 大会登台演讲时,明确阐述了 C++ 中的 “零成本抽象” 这一理念。 一、零成本抽象概念 Bjarne Stroustrup提出的零成本抽象概念,是指在编程中使用高级抽象机制时,不会产生…

Docker 安装 Jenkins:2.346.3

准备:已安装Docker,已配置服务器安全组规则 1581 1、拉取镜像 [rootTseng ~]# docker pull jenkins/jenkins:2.346.3 2.346.3: Pulling from jenkins/jenkins 001c52e26ad5: Pull complete 6b8dd635df38: Pull complete 2ba4c74fd680: Pull complet…

分布式事物XA、BASE、TCC、SAGA、AT

分布式事务——Seata 一、Seata的架构: 1、什么是Seata: 它是一款分布式事务解决方案。官网查看:Seata 2.执行过程 在分布式事务中,会有一个入口方法去调用各个微服务,每一个微服务都有一个分支事务,因…

分布式日志系统设计

一、分布式日志系统定义 分布式日志系统是一种用于收集、存储和分析大规模分布式系统日志的系统。它可以帮助开发人员和系统管理员实时监控和调试系统,提高系统可靠性和可用性,同时也可以用于日志分析和故障排查。 二、简单设计思路 日志收集&#xff…

VSCode设置字体

参考文章:【面向小白】vscode最佳实践(2)—— 字体设置(fira code更纱黑体),这篇文章末尾给了安装字体的链接。 配置的字体还是很好看的。 ‘Fira Code Retina’, ‘Sarasa Mono Sc’ 需要注意的一个点&am…

leaflet 双屏对比

本章主要讲的是leaflet的双屏对比,本文参考了插件:Leaflet.Sync,我这里对原有的文件进行了重写,去掉了一部分不需要的内容,增加了flyTo和panTo方法,新的方法,如果需要可以自行下载资源。 目录 …

什么是语义空间?

一、概念 今天我们来聊一聊一个比较抽象的概念——语义空间。语义空间(Semantic Space)是自然语言处理(NLP)领域中一个重要的概念,在语义空间中,文本中的语义信息通过数学的方式来表示和处理。语义空间是一…

Linux系统nginx版本升级

最近公司漏扫有涉及到需要升级nginx的部分, 以下是一些总结经验 检查当前nginx版本 执行命令: nginx -V 如果没有设置环境变量则需要进入到nginx目录sbin目录下执行: ./nginx -V 下载最新版nginx nginx下载地址: https://nginx.org/en/download.html 1)选择稳定版本 wget h…

如何高效的向AI大模型提问? - 提示工程Prompt Engineering

大模型的输入,决定了大模型的输出,所以一个符合要求的提问Prompt起到关键作用。 以下是关于提示工程Prompt Engineering主要方法的详细表格,包括每种方法的优点、缺点、应用场景以及具体示例: 主要方法优点缺点应用场景示例明确性…

QT 多级嵌套结构体,遍历成员--半自动。<模板+宏定义>QTreeWidget树结构显示

Qt的QTreeWidget来显示嵌套结构体的成员&#xff0c;并以树形结构展示。 #include <QApplication> #include <QTreeWidget> #include <QTreeWidgetItem> #include <QString> #include <cstdint>// 假设这些是你的结构体定义 struct BaseMeterPa…

鸿蒙实现数据管理

目录&#xff1a; 1、鸿蒙实现数据管理的三种方式2、用户首选项3、键值型数据管理3.1、获取KVManager实例&#xff0c;用于管理数据库对象3.2、创建并获取键值数据库3.3、调用put()方法向键值数据库中插入数据3.4、调用get()方法获取指定键的值3.5、调用delete()方法删除指定键…