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

news2024/11/23 14:58:59

什么是装饰器模式?

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

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

装饰模式(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() float64
    Description() 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.coloradmin.cn/o/1406160.html

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

相关文章

获取b站目录

参考链接&#xff1a; JS获取B站视频选集目录 Week6 - 知乎 代码 var x document.getElementsByClassName("clickitem"); var i; for (i 0; i < x.length; i) {var page_num x[i].getElementsByClassName("page-num")[0].innerText;var part x[i…

huggingface学习|云服务器部署Grounded-Segment-Anything:bug总会一个一个一个一个又一个的解决的

文章目录 一、环境部署&#xff08;一&#xff09;模型下载&#xff08;二&#xff09;环境配置&#xff08;三&#xff09;库的安装 二、运行&#xff08;一&#xff09; 运行grounding_dino_demo.py文件&#xff08;二&#xff09;运行grounded_sam_demo.py文件&#xff08;三…

[反转链表] [合并两个有序链表][分割链表]

这里写目录标题 反转链表合并两个有序链表分割链表 反转链表 1、题目&#xff1a; 2.思路  思路1&#xff1a;建立一个newHead,取一个节点进行头插。具体做法如下&#xff01; 建立一个newHead(新头)&#xff0c;由于一个节点里面存的是下一个节点的地址&#xff0c;如果取…

华夏基金“冰火两重天”:产品增量不增值,靠什么赢得用户?

近日&#xff0c;华夏基金发布关于华夏野村日经225交易型开放式指数证券投资基金&#xff08;QDII&#xff09;&#xff08;下称“华夏野村日经ETF”&#xff09;二级市场交易价格溢价风险提示及临时停牌公告。 公告内容显示&#xff0c;华夏野村日经ETF二级市场交易价格明显高…

DFT计算杂谈调查问卷

为更好了解公众号受众对于DFT计算的了解情况以及目标需求&#xff0c;目的以更好更准确并实用地推送给公众号受众所需要的文章&#xff0c;所以本次推送发布调查问卷并收集填写者相关信息。 调查问卷调查内容仅与公众号运营和DFT计算相关&#xff0c;所收集信息仅用作公众号受众…

如何选择和配置适合医院病历管理系统的MySQL版本?

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

7+细胞焦亡+ceRNA+实验验证,如何脱离套路求创新?

导语 今天给同学们分享一篇生信文章“Dissection of pyroptosis-related prognostic signature and CASP6-mediated regulation in pancreatic adenocarcinoma: new sights to clinical decision-making”&#xff0c;这篇文章发表在Apoptosis期刊上&#xff0c;影响因子为7.2。…

操作系统的灵魂--MMU详解

虚拟内存是现代操作系统中最伟大的发明之一。它为每个进程提供了一个一致的、私有的地址空间&#xff0c;让每个进程产生了一种自己在独享主存的错觉。 为了讲清楚MMU是如何一步一步完成地址翻译&#xff0c;取出数据的&#xff0c;本篇文章在前4节中讲解了虚拟内存中一些重要…

Aspx漏洞总结

第一部分&#xff0c;.NET项目当中的dll都可以进行反编译&#xff1a; 在java中有很多jar包&#xff0c;而在.NET框架中的bin中对应有很多DLL文件&#xff0c;bin下面都是可执行文件&#xff0c;这些文件都是很多代码封装的&#xff0c;想要查看源码&#xff0c;都需要通过反编…

vscode运行python,终端能正常运行,输出(Code Runner)不能正常运行

右键->Run Code报错&#xff1a; [Done] exited with code9009 in 0.111 seconds 我的解决方案&#xff1a;仔细检查自己选的python.exe&#xff08;解释器&#xff09;在path环境变量中是否存在或路径是否正确&#xff01;&#xff01;&#xff01; 我就是太自信了&#xf…

STL第三讲

第三讲 stl六大部件&#xff1a;算法是函数模板&#xff0c;其他的是类模板 算法形式&#xff1a;传入两个迭代器&#xff08;第三个参数可能有&#xff1a;一个比较的准则 算法需要的所有信息从迭代器获取 迭代器分类 基于红黑树的结构是双向迭代器&#xff1b; 基于hash的取…

idea——git提交到本地记录如何退回/删除

目录 一、git提交到本地记录如何退回/删除 一、git提交到本地记录如何退回/删除 git提交到本地记录&#xff0c;如下图【更新】记录&#xff0c;表示本次提交到git本地需要退回/删除的操作&#xff1a; 选中项目&#xff0c;右键点击【git】——>【Show History】——>…

苹果笔记本MacBook电脑怎么卸载软件?三种方法快速卸载软件

苹果笔记本MacBook电脑是一款非常流行的电脑&#xff0c;但是有时候我们可能需要卸载一些不需要的软件。下面是一些简单的步骤&#xff0c;可以帮助您在MacBook电脑上卸载软件。 苹果笔记本MacBook电脑怎么卸载软件&#xff1f;三种实用方法快速卸载软件&#xff01; 方法一&a…

【数据分享】2023年全球范围土壤数据集HWSD2.0(7个土壤深度/40多种土壤指标)

土壤数据&#xff0c;包括土壤类型、土壤酸碱度、土壤沙含量等指标&#xff0c;对于农业、林业、园艺、环境保护等领域都非常重要。 本次我们为大家带来的是2023年1月份发布的全球范围的土壤数据库。该数据的核心信息如下&#xff1a; ①该数据是基于联合国粮农组织&#xff0…

云HIS为连锁医院机构提供统一医院管理解决方案

云HIS重建统一的信息架构体系&#xff0c;重构管理服务流程&#xff0c;重造病人服务环境&#xff0c;向不同类型的医疗机构提供SaaS化HIS服务解决方案。 云HIS优势 1、云端数据优势 在传统的HIS模式里&#xff0c;数据存于医院本身的服务器机组&#xff0c;一旦发生故障&…

Python学习04—基本图形绘制

通过一个案例来初步认识Python的图形绘制 案例&#xff1a;绘制Python蟒蛇 #PythonDraw.py import turtle turtle.setup(650,350,200,200) turtle.penup() turtle.fd(-250) turtle.pendown() turtle.pensize(25) turtle.pencolor("purple") turtle.seth(-40) for i…

使用WAF防御网络上的隐蔽威胁之代码执行攻击

什么是代码执行攻击&#xff1f; 攻击者通过漏洞在目标系统上运行恶意代码。 这通常是由于应用程序或系统的安全漏洞&#xff0c;如输入验证不足、软件缺陷或配置错误。这些漏洞为攻击者提供了注入和执行恶意代码的机会。 攻击的类型 远程代码执行&#xff08;RCE&#xff…

linux中用户及用户组信息

1&#xff0c;linux通过用户名和口令来验证用户的身份。 2&#xff0c;几个用户可以组成一个用户组。 3&#xff0c;useradd工具添加用户&#xff0c;groupadd命令添加用户组。 4&#xff0c;history 命令查看用户在Shell中执行命令的历史记录。 5&#xff0c;userdel命令删…

jsjiami.v7介绍

jsjiami.v7介绍 jsjiami.v7是一款在线的JavaScript加密工具&#xff0c;它可以对JavaScript代码进行混淆、压缩、加密等操作&#xff0c;提高代码的安全性和运行效率。jsjiami.v7是jsjiami.v6的升级版&#xff0c;它在2023年1月17日发布&#xff0c;支持新版ES语法&#xff0c…

第二百八十四回

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了下拉刷新组件相关的内容&#xff0c;本章回中将介绍WillPopScope组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的WillPopScope组件是一种事件拦截类组件&#xff0c;它没有具体…