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

什么是装饰器模式?

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

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

装饰模式(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.mzph.cn/news/642876.shtml

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

相关文章

【开发随想】如何快速入手一个Linux开源项目

🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd🌐系列专栏:开发随想&#…

记录 js 过滤到tree上面的多余的数据

代码如下(示例): filterTree(arr, ids,firsttrue) {if(first){//首次传入深度克隆数据防止修改源数据arrJSON.parse(JSON.stringify(arr))}let emptyArr [];for (let item of arr) {if (ids.includes(item.id)) {if (item.children &&am…

【Foxmail】客户端发送邮件错误:SSL Recv :服务器断开连接, errorCode: 6

Foxmail客户端发送邮件提示:SSL Recv :服务器断开连接, errorCode: 6 错误代码 处理方式: 去邮箱生成新的16位授权码,输入到 密码框 内即可。 注:一旦开通授权码,在Foxmail验证时 密码框 里输入的就是 授权码

shell脚本概念构成及脚本变量详解

目录 一、前言 1、程序编程风格 2、编程语言 3、编程的三种处理逻辑 二、shell脚本 1、shell脚本基础 1.1 什么是shell 1.1.1 shell的概念 1.1.2 linux中常见的shell类型及信息 1.1.3 shell脚本的功能 1.2 shell脚本及构成 1.3 shell脚本执行方式 1.4 脚本错误调试…

spring和springboot的区别

在当今的软件开发领域,Spring和Spring Boot无疑是Java开发者最常用的框架之一。尽管它们都源于Spring项目,但它们在设计和使用上有很大的不同。本文将深入探讨Spring和Spring Boot之间的主要区别,以及为什么有时候选择其中一个而不是另一个是…

STL标准库(二)序列容器之array

容器 容器的本质是类模板,分为序列容器和关联容器 序列容器 array 固定数组 应用包含arrry库 vector 动态数组 应用包含 vector库 deque 双端队列 list 双向链表 forward_list 单向链表 stack 栈 queue 队列 prority 优先队列 array应用 int main() { …

现代密码学基础(2)

目录 一. 介绍 二. 举例:移位密码 (1)密文概率 (2)明文概率 三. 举例:多字母的移位密码 四. 完美安全 五. 举例:双子母的移位密码 六. 从密文角度看完美安全 七. 完美保密性质 一. 介绍…

NVIDIA 再现逆天刀法,千元级 RTX 新卡曝光

这年头,价格 1 字开头入门甜品显卡几乎真就成 N、A 两家弃子了。 以 NVIDIA RTX 4060 与 AMD RX 7600 为例,这两块显卡同为两家新品中最低端型号,其价格直接来到 2K 左右起步。 要知道目前很多普通用户选购一台日常办公、游戏电脑主机&#…

vue(vue2)使用svg格式图标

先安装插件 配置svg文件夹,新建icons文件,svg文件夹放svg后缀文件 index.js文件中的配置 import Vue from "vue" import svgIcon from "/common/iconSvg/index.vue"Vue.component(svg-icon,svgIcon) //挂载全局组件//下面…

Python with Office 054 - Work with Word - 7-9 插入图像 (3)

近日详细学习了寒冰老师的很好的书《让Python遇上Office》,总结了系列视频。 这个是其中的一集:如何在Word中插入图像,我会陆续分享其他的视频并加上相应说明 https://www.ixigua.com/7319498175104942643?logTage9d15418663166a05d10

Java 一个数组集合List<People> 赋值给另一个数组集合List<NewPeople> ,两个数组集合属性部分一致。

Java 一个数组集合List 赋值给另一个数组集合List ,两个数组集合属性部分一致。 下面是一个Demo, 具体要根据自己的业务调整。 import java.util.ArrayList; import java.util.List;class People {private String name;private int age;private String address;publ…

小程序商城能不能自己开发?

在数字化时代,小程序商城已经成为商家拓展销售渠道、提升品牌影响力的重要工具。那么,商家能否自己动手开发小程序商城呢?答案是肯定的。接下来,以乔拓云为例,为大家详细介绍如何自己搭建小程序商城。 首先&#xff0c…

ntp时间适配服务器和ssh免密登录

1.配置ntp时间服务器,确保客户端主机能和服务主机同步时间 服务端server向阿里时间服务器进行时间同步 第一步:定位服务端server #安装软件 [rootserver ~]# yum install chrony -y # 编辑配置文件,定位第3行,修改…

75.网游逆向分析与插件开发-背包的获取-背包结构与指针的逆向分析

内容参考于:易道云信息技术研究院VIP课 上一个内容:物品名称与物品编号的映射关系分析-CSDN博客 通过上一个内容已经可以通过物品的id得到一个名字,知道了它的算法,它的算法自己封装好了,我们直接用就好,…

机器学习之numpy库

机器学习之numpy库 numpy库概述numpy库历史numpy的核心numpy基础ndarray数组内存中的ndarray对象ndarray数组对象的特点ndarray数组对象的创建ndarray对象属性的基本操作数组的维度元素的类型数组元素的个数数组元素索引(下标) ndarray对象数组的自定义类型切片操作一维数组切片…

【趣味游戏-08】20240123点兵点将点到谁就是谁(列表倒置reverse)

背景需求: 上个月,看到大4班一个孩子在玩“点兵点将点到谁就是谁”的小游戏,他在桌上摆放两排奥特曼卡片,然后点着数“点兵点将点到谁就是谁”,第10次点击的卡片,拿起来与同伴的卡片进行交换。他是从第一排…

npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED

npm install时报错code CERT_HAS_EXPIRED 一、报错情况二、解决方案 一、报错情况 一直用的好好的,突然今天发现npm install 出问题了,具体报错如下: npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED npm ERR! request to…

unity项目《样板间展示》开发:火焰和UI设计

第二章:火焰和UI设计 前言一、火焰模型管理灶台火焰壁炉火焰 二、电视机播放三、UI设计结语 前言 这次带大家从0到1做一个unity项目:《样板间展示》。 顾名思义,项目内容是展示样板间,即玩家可以与房间中的物体、家具进行交互。 至…

30天零售应用构建挑战:低代码平台的惊人潜力

随着零售业格局的不断演变,零售商正被迫在一个日益活跃、竞争日益激烈的客户驱动型市场中展开竞争。随着互联网上产品信息和评论的出现,消费者的态度发生了巨大的变化——购物者不再依赖销售人员来获取信息。他们现在知道的和许多零售销售人员一样多&…

一些小方法【二】

本文为博主原创,未经授权,严禁转载及使用。 本文链接:https://blog.csdn.net/zyooooxie/article/details/127978957 之前写过一篇 介绍自己常用的方法, https://blog.csdn.net/zyooooxie/article/details/104494716 ,…