【设计模式】美团三面:你连装饰器都举不出例子?

什么是装饰器模式?

装饰器模式,这个设计模式其实和它的名字一样,非常容易理解。

想象一下,每天出门的时候,我们都会思考今天穿什么。睡**衣、睡裤加拖鞋,还是西装、领带加皮鞋?又或者说是,背心、短裤不穿鞋?**穿什么,不穿什么,都是可以随意更改的。而这,就是装饰器模式所应用的场景。

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

img

具体实现

装饰模式的实现中,我们需要一系列组件:抽象组件(Component)、具体组件(ConcreteComponent)以及装饰抽象类(Decorator)。

抽象组件定义了一个对象接口,可以给这些对象动态添加职责。具体组件是被装饰的对象,这个对象可以被一或多个装饰类装饰。装饰类即装饰抽象类,继承了抽象组件,并持有一个具体组件的引用,可以调用具体组件的方法,并可以在调用前后增加新的功能。

我们通过一个生活中的例子来具体理解:假设我们在一个咖啡店,首先会点一杯基础的咖啡,也就是ConcreteComponent;然后我们可能会要求加一份牛奶或者糖,这些就是Decorator,他们继承了咖啡接口,并且持有咖啡的引用,每次加一份牛奶或者糖的时候,我们其实是在装饰我们的咖啡。非常抱歉,我疏忽了。现在让我们继续刚才的咖啡店例子,我将用Java来说明装饰器模式是怎样工作的。

Java

首先,我们需要定义一个抽象咖啡类(Beverage):

public abstract class Beverage {String description = "Unknown Beverage";public String getDescription() {return description;}public abstract double cost();
}

然后,我们定义一种具体的咖啡(Espresso):

public class Espresso extends Beverage {public Espresso() {description = "Espresso";}public double cost() {return 1.99;}
}

接下来,我们需要定义一个抽象的装饰者(CondimentDecorator):

public abstract class CondimentDecorator extends Beverage {public abstract String getDescription();
}

最后,我们定义一种具体的装饰者,也就是我们的“加牛奶”操作(Milk):

public class Milk extends CondimentDecorator {Beverage beverage;public Milk(Beverage beverage) {this.beverage = beverage;}public String getDescription() {return beverage.getDescription() + ", Milk";}public double cost() {return .10 + beverage.cost();}
}

这样,当我们想要一杯加了牛奶的浓缩咖啡时,我们可以这样做:

Beverage beverage = new Espresso();
beverage = new Milk(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());

这就是装饰器模式的工作原理。你可以发现,通过这种方式,我们可以动态地为咖啡添加各种配料,而不需要修改原来的咖啡类。而且,由于所有的配料和咖啡都继承自同一个父类,我们可以将咖啡和配料无缝地组合在一起。

go

在Go里面,我们会使用一些嵌入和接口的技巧。

首先定义咖啡接口:

type Beverage interface {Cost() float64Description() string
}

然后定义一个基础的Espresso咖啡:

type Espresso struct {}func (e Espresso) Cost() float64 {return 1.99
}func (e Espresso) Description() string {return "Espresso"
}

接下来定义一个装饰者接口:

type CondimentDecorator struct {Beverage
}

最后我们来定义一种装饰者,也就是我们的加牛奶操作:

type Milk struct {CondimentDecorator
}func (m Milk) Cost() float64 {return 0.1 + m.Beverage.Cost()
}func (m Milk) Description() string {return m.Beverage.Description() + ", Milk"
}

我们就可以通过下面的方式来得到一杯加了牛奶的咖啡:

beverage := Espresso{}
bev_with_milk := Milk{CondimentDecorator: beverage}
fmt.Printf("%s $%.2f\n", bev_with_milk.Description(), bev_with_milk.Cost())

我们可以发现,通过这种方式,我们可以动态地为咖啡添加各种配料,而不需要修改原来的咖啡类。而且,由于所有的配料和咖啡都实现自同一个接口,我们可以将咖啡和配料无缝地组合在一起。

总结

装饰模式是设计模式中极其重要的一员,因为它的灵活性和弹性。这种模式适用于需要动态、透明地给对象添加职责的应用。只要理解得当,其使用的场景其实非常广泛。

然而,能力越大,责任越大。装饰模式也有其需要注意的地方。使用时要避免出现繁复和复杂的装饰层,否则不仅代码难以维护,更可能会出现各种疏漏和陷阱。

和造物者模式有什么区别?

装饰模式和造物者模式虽然都属于创建型模式,但区别在于:装饰模式关注的是给已有的对象添加功能,实现功能的可拓展,而不改变原有对象的结构;造物者模式则更多关注对象的创建过程,将对象的构造与表示分离,使同样的构建过程可以创建不同的表示。

简单说,装饰模式注重的是“动态扩展”,造物者模式注重的是“构造控制”。

和策略模式有什么区别?

装饰模式和策略模式在实现灵活性方面有些相似,但它们的应用场景和目标是不同的。

装饰模式主要用于动态地扩展一个对象的功能,而策略模式则主要用于抽象化一组算法,从而可以在运行时动态地选择算法。在装饰模式中,装饰者和被装饰对象通常有共同的超类,而在策略模式中,策略类和使用策略的上下文类通常没有共同的超类。

简单说,装饰者模式是结构型模式,注重扩展对象的功能;策略模式则是行为型模式,注重改变对象的行为。

如果上面的内容对你有帮助,请点赞收藏哦,我会分享更多的经验~

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql数据库DQL查询语言之表连接(联合查询)

表连接 关系字段:两表中有关联关系的字段 \关系字段:两表之间存在关系的字段 什么是表连接? 当我们的查询结果需要从多张表中获取时,此时应该让表之间建立连接,同时获取数据 内连接 特点:同时对连接双方做…

性能优化-HVX 指令介绍

「发表于知乎专栏《移动端算法优化》」 本文主要介绍了 HVX 指令相关的知识,包括 HVX 寄存器相关内容,指令的背景依赖,部分常用 intrinsic HVX 指令。具体指令的详细内容及使用还需阅读 HVX 的指令文档,以及细致的实践操作。 &…

(十二)Head first design patterns代理模式(c++)

代理模式 代理模式:创建一个proxy对象,并为这个对象提供替身或者占位符以对这个对象进行控制。 典型例子:智能指针... 例子:比如说有一个talk接口,所有的people需要实现talk接口。但有些人有唱歌技能。不能在talk接…

Flink中的容错机制

一.容错机制 在Flink中,有一套完整的容错机制来保证故障后的恢复,其中最重要的就是检查点。 1.1 检查点(Checkpoint) 在流处理中,我们可以用存档读档的思路,将之前某个时间点的所有状态保存下来&#xf…

JAVA 学习 面试(六)数据类型与方法

数据类型 基本数据类型 为什么float3.4报错 3.4 默认是浮点double类型的,如果赋值给float是向下转型,会出现精度缺失,,需要强制转换 Switch支持的数据类型? byte、short、int、char 、 enum 、 String 基本类型与包…

使用 Swift 代码优化项目编译速度

引言 软件的性能是评价一个软件质量的重要指标,尤其在今天这个时代,性能已成为大型项目不可或缺的考虑因素之一。对于用户量极大的软件,如网银系统、在线购物商城等,更是必须保证其高效稳定的性能。在这种背景下,优化…

Python-基础篇-类与对象/面向对象程序设计-py脚本

面向对象基础 第一个面向对象 class Cat:def eat(self):print("小猫爱吃鱼")def drink(self):print("小猫要喝水")# 创建猫对象 tom Cat()tom.eat() tom.drink()print(tom)addr id(tom) print("%x" % addr)新建两个猫对象 class Cat:def ea…

Dockerfile-xxxx

1、Dockerfile-server FROM openjdk:8-jdk-alpine WORKDIR /app COPY . . CMD java -Xms1536M -Xmx1536M -XX:UseG1GC -jar -Dlog4j2.formatMsgNoLookupstrue -Dloader.pathresources,lib -Duser.timezoneGMT-05 /app/server-main-1.0.0.jar 2、Dockerfile-bgd #FROM openjdk…

MySQL-SQL-DQL

DQL-介绍 DQL-语法 基本查询 1、查询多个字段 2、设置别名 3、去除重复记录 条件查询 1、语法 2、条件 聚合函数 1、介绍 2、常见的聚合函数 3、语法 分组查询 1、语法 2、where与having区别 排序查询 1、语法 2、排序方式 分页查询 1、语法 DQL-执行顺序

【代码随想录】刷题笔记Day54

前言 差单调栈就结束代码随想录一刷啦,回家二刷打算改用python补充进博客,小涛加油!!! 647. 回文子串 - 力扣(LeetCode) 双指针法 中心点外扩,注意中心点可能有一个元素可能有两个…

MacOS受欢迎的数据库开发工具 Navicat Premium 15 中文版

Navicat Premium 15 Mac是一款数据库管理工具,提供了一个全面的解决方案,用于连接、管理和维护各种数据库系统。以下是Navicat Premium 15 Mac的一些主要功能和特点: 软件下载:Navicat Premium 15 中文版下载 多平台支持&#xff…

PLC从HTTP服务端获取JSON文件,解析数据到寄存器

智能网关IGT-DSER集成了多种PLC协议,方便实现各种PLC与HTTP服务端之间通讯。通过网关的参数配置软件绑定JSON文件的字段与PLC寄存器地址,配置URL,即可采用POST命令,将JSON文件提交给HTTP的服务端; 服务端有返回的JSON&…

从 Context 看 Go 设计模式:接口、封装和并发控制

文章目录 Context 的基本结构Context 的实现和传递机制为什么 Context 不直接传递指针案例:DataStore结论 在 Go 语言中, context 包是并发编程的核心,用于传递取消信号和请求范围的值。但其传值机制,特别是为什么不通过指针传递…

RTDETR 引入 UniRepLKNet:用于音频、视频、点云、时间序列和图像识别的通用感知大卷积神经网络 | DRepConv

大卷积神经网络(ConvNets)近来受到了广泛研究关注,但存在两个未解决且需要进一步研究的关键问题。1)现有大卷积神经网络的架构主要遵循传统ConvNets或变压器的设计原则,而针对大卷积神经网络的架构设计仍未得到解决。2)随着变压器在多个领域的主导地位,有待研究ConvNets…

Ubuntu Desktop 隐藏 / 显示文件和文件夹

Ubuntu Desktop 隐藏 / 显示文件和文件夹 1. GUI hot key2. Show hidden and backup filesReferences 1. GUI hot key Ctrl H: 隐藏 / 显示文件和文件夹 2. Show hidden and backup files Edit -> Preferences -> Views References [1] Yongqiang Cheng, https://yo…

【分布式技术】消息队列Kafka

目录 一、Kafka概述 二、消息队列Kafka的好处 三、消息队列Kafka的两种模式 四、Kafka 1、Kafka 定义 2、Kafka 简介 3、Kafka 的特性 五、Kafka的系统架构 六、实操部署Kafka集群 步骤一:在每一个zookeeper节点上完成kafka部署 ​编辑 步骤二&#xff1a…

【数据结构】 链栈的基本操作 (C语言版)

目录 一、链栈 1、链栈的定义: 2、链栈的优缺点: 二、链栈的基本操作算法(C语言) 1、宏定义 2、创建结构体 3、链栈的初始化 4、链栈的进栈 5、链栈的出栈 6、获取栈顶元素 7、栈的遍历输出 8、链栈的判空 9、求链…

一周时间,开发了一款封面图生成工具

介绍 这是一款封面图的制作工具,根据简单的配置即可生成一张好看的封面图,目前已有七款主题可以选择。做这个工具的初衷来自平时写文章,都为封面图发愁,去图片 网站上搜索很难找到满意的,而且当你要的图如果要搭配上文…

Eureka整合seata分布式事务

文章目录 一、分布式事务存在的问题二、分布式事务理论三、认识SeataSeata分布式事务解决方案1、XA模式2、AT模式3、SAGA模式4.SAGA模式优缺点:5.四种模式对比 四、微服务整合Seata AT案例Seata配置微服务整合2.1、父工程项目创建引入依赖 2.2、Eureka集群搭建2.3、…

02-编程猜谜游戏

上一篇:01-开始Rust之旅 本章通过演示如何在实际程序中使用 Rust,你将了解 let 、 match 、方法、关联函数、外部crate等基础知识。 本章将实现一个经典的初学者编程问题:猜谜游戏。 工作原理如下:程序将随机生成一个介于 1 和 10…