设计模式——行为模式

news/2024/9/19 4:46:54/ 标签: 设计模式

注意,设计模式的实现并不唯一。

责任链模式

将请求顺序的传递给每一个接收者,直到有一个接收者做出处理。或者一个接收者处理之后继续传递给下一个接收者。

例如 QT 的信号机制。

与装饰器模式的不同:

“责任链的管理者可以相互独立地执行一切操作, 还可以随时停止传递请求。 另一方面, 各种装饰可以在遵循基本接口的情况下扩展对象的行为。 此外, 装饰无法中断请求的传递。”

 

 “中央批下来的公款,本来应该全给到底层,但是中间每层都做一些额外的操作。”

在这个例子中,如果本来中央可以直接给到底层,但是没给,就是要让每层过一遍,这叫装饰模式。但是如果中央没办法直接给到底层,不得已必须层层传递,这叫责任链模式。

class Request;class Layer {virtual bool handle(Request request) = 0;
};class LayerImpl : public Layer {bool handle(Request request) override {if ( /* 我能处理 */ ) {// 处理return true;}for (auto layer : next_layers) {if (layer.handle(request)) {return true;}}}
private:std::vector<Layer > next_layers;
};

 命令模式

当一项业务操作代码会被复制成多份时,将其设计为一个命令。

例如,通常编辑器上有“复制”按钮,也可以通过 Ctrl+C 复制,这两项都是对剪切板的操作,可以把它们叫做 copy 命令,发送至剪切板对象。

class String;class Command {virtual void execute() = 0;
};class CopyCommand : public Command {void execute() override;
};class CutCommand : public Command {void execute() override;
};class Button {void set_on_click(Command command);void on_click() {command.execute();}private:Command command;
};class Shortcut {void set_shortcut(String key, Command command);
};int main()
{CopyCommand copy_command;CutCommand cut_command;Shortcut shortcuts;Button copy_button;copy_button.set_on_click(copy_command);shortcuts.set_shortcut("Ctrl+C", copy_command);Button cut_button;cut_button.set_on_click(cut_command);shortcuts.set_shortcuts("Ctrl+X", cut_command);
}

个人理解:

把操作变成对象,用于存储、传递。

 迭代器模式

当你希望你操作的对象在不暴露数据成员的情况下提供遍历方法时,你可以要求该对象提供迭代器。

你希望在不暴露数据成员的情况下提供访问数据成员的方法时,你可以提供迭代器。

例如 std::vector,std::queue。

class Spammer;
class Stringclass Server {class SpammerIterator {virtual bool next() = 0;virtual String get_email() = 0;};void email_to(SpammerIterator spammer);
};class WeChatContact {class WechatSpammerIterator : public SpammarIterator {bool next() override;String get_email() override;}SpammerIterator* create_iterator();private:std::vector<Spammer> spammers;
};class QQContact {class QQSpammerIterator : public SpammarIterator {bool next() override;String get_email() override;}SpammerIterator* create_iterator();private:std::vector<Spammer> spammers;
};int main()
{WeChatContact wechat_contact;QQContact qq_contact;Server server;SpammerIterator* spammer_iterator;if (/*using WeChat*/) {spammer_iterator = wechat_contact.create_iterator();}else if (/*using QQ*/) {spammer_iterator = qq_contact.create_iterator();}while (spammer_iterator.next()) {server.email_to(spammer_iterator->get_email();}
}

你也可以提供一个 for_each 方法。

中介者模式

多个对象之间的关系错综复杂,把这些关系抽取为单独的一个类,这个类是中介者。

与其他模式的区别

  • 责任链模式:一个请求——多个接收者
  • 命令模式:多个对象发出同一个请求
  • 中介者模式:抽象出请求者与接收者之间的联系
  • 观察者:接受者选择请求者

 例如在 A,B,C 三个对象中,每个对象负责一项业务。你希望 A 业务完成后,要修改 B 对象的状态。B 业务完成后,修改 C 对象的状态;C 业务完成后,修改 A 对象的状态。抽取出一个类,持有对三个对象的引用,当 A,B,C 任一业务完成后通知此对象,此对象根据事件通知执行后续。

enum class Events;class Mediator {void notify(Events event) {if (/* event 为 A */) {b.set_data();}else if (/* event 为 B */) {c.set_data();}else if (/* event 为 C */) {a.set_data();}}private:A& a;B& b;C& c;
};class A {void server() {// 业务 Amediator.notify(Events::A);}void set_data();private:Mediator& mediator;
};class B {void server() {// 业务 Bmediator.notify(Events::B);}void set_data();private:Mediator& mediator;
};class C {void server() {// 业务 Cmediator.notify(Events::C);}void set_data();private:Mediator& mediator;
};

备忘录模式

当你需要为对象创建快照和从快照中还原对象时,这项工作可以委托给一个快照对象,从而避免暴露对象的数据成员。

class Data; // 二进制数据class Object {
public:// 作为嵌套类可以访问 Object 的成员class SnapShot {Data create();void restore(Data data);    private:Object& object;};
private:int a;double b;std::string c;
};

观察者模式

又称订阅者模式。

把请求者发送请求到接收者 改为 接受者订阅请求者的请求。

例如 Kafka,逛不同网站时订阅该网站的商品邮件。

class Request;
class Endpoint; // 这个名称通常表示 IP:PORT,例如 "127.0.0.1:8080"class Server {void on_request(Request request) {for (auto subscriber : subscribers) {send(subscriber, request);}}void register(Endpoint endpoint) {subscribers.push_back(endpoint);}private:std::vector<Endpoint> subscribers;
};class Client {Endpoint get_endpoint();void receive();void on_request(Request request) {// 处理请求}
};

状态模式

相同的接口在不同状态下表现出不同的行为。

例如视频暂停时、播放时,双击屏幕的行为不同。

class State {virtual void on_double_click() = 0;
};class PauseState {void on_double_click() override {// 隐藏暂停图标,继续播放}
};class PlayingState {void on_double_click() override {// 显示暂停图标,暂停播放}
};class VideoPlayer {void change_state(State state);void on_double_click() {state.on_double_click();}
};

策略模式

一个需要替换不同算法的场景中,我们可以将算法抽象出来。

例如地图app中,从一个位置到另一个位置,因为交通方式不同,有不同的路线和算法。

class Strategy {virtual int execute(int a, int b) = 0;
};class AddStrategy {int execute(int a, int b) override {return a + b;}
};class SubStrategy {int execute(int a, int b) override {return a - b;}
};class MulStrategy {int execute(int a, int b) override {return a * b;}
};int main()
{int a,b;Strategy strategy;if (/*add*/) {strategy = AddStrategy();}else if (/*sub*/) {strategy = SubStrategy();}else if (/*mul*/) {strategy = MulStrategy();}strategy.execute();
}

在某些语言中,你可以使用函数对象代替多态。

与其它模式的关系:

  • 状态模式包含了具体了业务。策略模式期望算法无需关心业务。
  • 命令模式包装操作。策略模式抽象算法。
  • 装饰模式更改外表。策略模式替换内核。

 模板方法模式

将一系列步骤抽象,让客户端可以替换每一个步骤的工作。

  • 抽象步骤必须由各个子类来实现
  • 可选步骤已有一些默认实现, 但仍可在需要时进行重写

“还有另一种名为钩子的步骤。 钩子是内容为空的可选步骤。 即使不重写钩子, 模板方法也能工作。 钩子通常放置在算法重要步骤的前后, 为子类提供额外的算法扩展点。”

// 使用函数对象代替多态
class Function;class Work {void set_step1(Function step1);void set_hook(Function hook);void set_step2(Function step2);void set_step3(Function step3);void set_step4(Function step4);void work() {step1();hook();step2();step3();step4();}private:Function step1;Function hook;Function step2;Function step3;Function step4;
};

class BaseWork {virtual void step1() = 0;virtual void hook(); // 默认实现virtual void step2() = 0;virtual void step3() = 0;virtual void step4() = 0;void work() {step1();hook();step2();step3();step4();}
};class Work : public BaseWork {void step1() override;void step2() override;void step3() override;void step4() override;
};

访问者模式

访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。

 对于继承自 X 的 A,B,C 三个派生类,它们重载的同一个算法函数实现不同,如何实现?简单,override 即可。如果甲方要求修改算法,但又不希望调整已经稳定的 A,B,C 的代码,该如何呢?

简单的重载无法满足该需求。访问者模式将算法实现在作用对象外部,从而不影响作用对象的代码。

class Parameters;class Visitor {void for_A(Parameters param) {// 对 A 的算法}void for_B(Parameters param) {// 对 B 的算法}void for_C(Parameters param) {// 对 C 的算法}
};class Base {virtual accept(Visitor visitor) = 0;
};class A : public Base {void accept(Visitor visitor) {visitor.for_A(Parameters());}
};class B : public Base {void accept(Visitor visitor) {visitor.for_B(Parameters());}
};class C : public Base {void accept(Visitor visitor) {visitor.for_C(Parameters());}
};


http://www.ppmy.cn/news/1520349.html

相关文章

Cornerstone3D Tools对影像进行交互(上篇)-基础交互工具及同步器

⛳️ 前言 在我们日常需求中&#xff0c;除了需要对影像进行可视化展示外&#xff0c;大多数场景下还需要对影像进行调整、注释、分割等操作。Cornerstone3DTools库则支持大多数需要的交互功能。CornerstoneTools支持的工具类型主要分为以下4类&#xff1a; 基础交互类工具&am…

k8s-pod 实战五 (Startup Probe 详细分析)

一、Startup Probe 详细分析 Startup Probe Startup Probe 用于检测容器是否完成启动。它的目的是取代 Liveness Probe,在容器启动时提供一个更长的检测时间窗口。Startup Probe 是为了处理启动时间较长的应用程序,避免在启动过程中因 Liveness Probe 失败而导致容器重启。…

【系统架构设计师-2021年】综合知识-答案及详解

【第1题】 某计算机系统页面大小为4K&#xff0c;进程P1的页面变换表如下图所示&#xff0c;看P1要访问数据的逻辑地址为十六进制1B1AH,那么该逻辑地址经过变换后,其对应的物理地址应为十六进制&#xff08; &#xff09;。 答案解析 本题考查页式存储中的逻辑地址转物理地…

力扣632.最小区间

力扣632.最小区间 贪心 最小堆 用一个小根堆维护K个数其中最小的算完结果后弹出&#xff0c;再补一个进去 class Solution {public:vector<int> smallestRange(vector<vector<int>>& nums) {int l0,rINT_MAX;int n nums.size();//记录下一个位置的下…

git服务搭建

纯git server 软件安装 环境:ubuntu16.0.4 安装Git-Core:sudo apt-get install python-setuptools 安装openssh-server和openssh-client:sudo apt-get install openssh-server openssh-client安装python tool:sudo apt-get install python-setuptools安装gitosis: git clon…

时间格式--cotroller传递时间参数

时间格式–cotroller传递时间参数 我们的前端控制器controller代码&#xff0c; package com.forge.controller;import com.forge.common.Result; import com.forge.entity.Doctor; import com.forge.service.TestService; import lombok.extern.slf4j.Slf4j; import org.spr…

Android使用addr2line分析Native Crash

NDK提供的工具将函数地址解析为具体的函数名和行数才能进一步分析问题。 常用的地址转换工具有addr2line、ndk-stack等&#xff0c;个人比较喜欢addr2line&#xff0c;所以接下来介绍下该工具的基本使用方式 日常使用过程中&#xff0c;只需要关注-C -f -e三个参数即可 // -…

浅析JVM invokedynamic指令和Java Lambda语法|得物技术

一、导语 尽管近年来JDK的版本发布愈发敏捷&#xff0c;当前最新版本号已经20&#xff0c;但是日常使用中&#xff0c;JDK8还是占据了统治地位。 你发任你发&#xff0c;我用Java8&#xff1a;【Jetbrains】2023 开发者生态系统现状 - https://www.jetbrains.com/zh-cn/lp/dev…

都2024年了你还缺客源?十分钟教你如何获取!

你是否还在为如何找到精准的客源而烦恼&#xff1f;别担心&#xff0c;今天我们就来分享一些客源采集方法&#xff0c;让你十分钟内掌握技巧&#xff0c;轻松获取全国各地各行各业的客源。 精准采集客源 1. 拓客工具 专业的拓客工具可以帮助你精准地采集到全国各地的客源信息。…

无人机之遥控器防水性能篇

无人机遥控器的防水性能是评估其耐用性和适应不同环境能力的重要指标。随着无人机技术的不断发展&#xff0c;越来越多的遥控器在设计时融入了防水元素&#xff0c;以满足用户在不同天气条件下的使用需求。以下是对无人机遥控器防水性能的详细探讨&#xff1a; 一、防水等级与…

Redis 入门到精通1

一、String&#xff08;字符串&#xff09; 特点&#xff1a; 最基本的数据类型&#xff0c;二进制安全&#xff0c;可以存储任何数据&#xff0c;比如图片或者序列化的对象。一个 key 对应一个 value。 常用命令及示例&#xff1a; SET key value&#xff1a;设置一个键值对。…

实战项目:俄罗斯方块(六)

文章目录 &#x1f34a;自我介绍&#x1f34a;图像界面绘制界面绘制界面显示代码运行结果 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家好&#xff0c;我是小珑也…

C语言典型例题60

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题4.1 统计全单位人员的平均工资。单位的人数是不固定的&#xff0c;工资数从键盘先后输入&#xff0c;当输入-1时&#xff0c;表示输入结束(前面输入的都是有效数字)。 代码&#xff1a; //《C程序设计教程&…

论文《Improving your graph neural networks:A High-Frequency Booster》笔记

【CLAR 2022 ICDMW】作者指出&#xff0c;现有的GNN模型主要关注于消息传递机制&#xff0c;但这些模型往往受限于低通滤波器的局限&#xff0c;导致在多层堆叠时性能下降。为了解决这个问题&#xff0c;论文提出了一种新的正则化方法&#xff0c;称为补全拉普拉斯正则化&#…

三防平板:定制化服务的趋势——以智慧医疗为例

随着科技的飞速发展&#xff0c;三防平板产品凭借其坚固耐用、适应复杂环境的特性&#xff0c;在众多行业领域中崭露头角。而在AI迅速增长的今天&#xff0c;AI智慧医疗成为了一个备受关注的热点&#xff0c;它不仅推动了医疗行业的数字化转型&#xff0c;也为三防平板产品的定…

linux 硬件 arm架构 汇编语言

1.cortex 1. Cortex-A 低功耗 消费类 ARM Cortex-A 系列处理器是一种广泛应用于 移动设备、嵌入式系统和物联网的高效能处理器&#xff0c;因其低功耗和高性能的特点而受到青睐。 2. Cortex-R 实时性 Cortex-R处理器针对高性能实时应用&#xff0c;例如硬盘控制器&#xff08;或…

挂载5T大容量外接硬盘到ubuntu

挂载5T大容量外接硬盘到ubuntu S1&#xff1a;查看硬盘 使用 $ sudo fdisk -l找到对应盘&#xff0c;例如下图所示 /dev/sdc S2: 创建分区 使用 $ sudo fdisk /dev/sdc对上硬盘进行创建分区&#xff1b;可以依次使用以下指令 m &#xff1a;查看命令&#xff1b; g &…

SQL 中 LIKE 和 REGEXP 的相同点与不同点解析

SQL 中 LIKE 和 REGEXP 的相同点与不同点解析 在数据库查询中&#xff0c;字符串匹配是非常常见的需求&#xff0c;而 SQL 提供了多种方式来实现这一功能&#xff0c;其中 LIKE 和 REGEXP 是两种常用的操作符。虽然它们都能用于字符串匹配&#xff0c;但它们在工作原理、匹配精…

前端面试:webSocket如何兼容低浏览器?

WebSocket 是一种用于全双工通信的协议&#xff0c;它可以在客户端和服务器之间建立持久的连接。尽管现代浏览器广泛支持 WebSocket&#xff0c;但对于一些低版本浏览器或不支持 WebSocket 的环境&#xff0c;我们需要考虑兼容性问题。以下是在低版本浏览器上兼容 WebSocket 的…

Hive Tutorial For Beginners

Hive Tutorial For Beginners 一、Hive历史&#xff08;History of Hive&#xff09; Facebook 在面对日益增长的大数据时&#xff0c;选择了 Hadoop 作为解决方案。 但问题在于&#xff0c;许多用户并不熟悉 Java 或其他编程语言&#xff0c;这使得使用 Hadoop 的 MapReduc…