【设计模式】行为型模式(二):策略模式、命令模式

行为型模式(二):策略模式、命令模式

  • 3.策略模式(Strategy)
    • 3.1 示例
      • 3.1.1 定义策略接口
      • 3.1.2 实现具体策略
      • 3.1.3 定义上下文类
      • 3.1.4 客户端代码
      • 3.1.5 输出结果
    • 3.2 总结
      • 3.2.1 优点
      • 3.2.2 缺点
  • 4.命令模式(Command)
    • 4.1 组成部分
    • 4.2 示例
      • 4.2.1 命令接口
      • 4.2.2 具体命令实现
      • 4.2.3 接收者
      • 4.2.4 调用者
      • 4.2.5 客户端
      • 4.2.6 输出结果
    • 4.3 总结
      • 4.3.1 优点
      • 4.3.2 缺点

3.策略模式(Strategy)

策略模式Strategy)是一种行为设计模式,它使你能在运行时改变对象的行为。下面是策略模式的几个关键点:

  • 定义一组算法:策略模式定义了一组可互换的算法(或行为)。这些算法封装在独立的类中,每个类实现一个特定的算法。
  • 封装变化:将变化的部分从不变的部分中分离出来,封装成独立的类,这样可以更容易地扩展和维护。
  • 运行时选择算法:客户端可以根据需要在运行时选择不同的算法(策略)来执行特定任务。

3.1 示例

假设你正在开发一个电商系统,需要根据不同的促销策略计算订单的最终价格。你可以定义一个 PromotionStrategy 接口,然后为不同的促销策略实现该接口,例如:

  • FixedDiscountStrategy:固定金额折扣
  • PercentageDiscountStrategy:百分比折扣
  • NoDiscountStrategy:无折扣

在订单类中,你可以使用 PromotionStrategy 接口来计算最终价格,并在运行时根据需要选择不同的策略。

3.1.1 定义策略接口

首先,定义一个策略接口 PromotionStrategy,该接口声明了一个计算折扣价格的方法 calculateDiscount

public interface PromotionStrategy {double calculateDiscount(double originalPrice);
}

3.1.2 实现具体策略

接下来,实现不同的促销策略,例如 固定金额折扣百分比折扣无折扣

public class FixedDiscountStrategy implements PromotionStrategy {private double discountAmount;public FixedDiscountStrategy(double discountAmount) {this.discountAmount = discountAmount;}@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice - discountAmount;}
}public class PercentageDiscountStrategy implements PromotionStrategy {private double discountRate;public PercentageDiscountStrategy(double discountRate) {this.discountRate = discountRate;}@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice * (1 - discountRate);}
}public class NoDiscountStrategy implements PromotionStrategy {@Overridepublic double calculateDiscount(double originalPrice) {return originalPrice;}
}

FixedDiscountStrategyPercentageDiscountStrategyNoDiscountStrategy 实现了 PromotionStrategy 接口,分别实现了固定金额折扣、百分比折扣和无折扣。

3.1.3 定义上下文类

上下文类 Order 使用 PromotionStrategy 接口来计算最终价格。上下文类可以在运行时选择不同的策略。

public class Order {private double originalPrice;private PromotionStrategy promotionStrategy;public Order(double originalPrice, PromotionStrategy promotionStrategy) {this.originalPrice = originalPrice;this.promotionStrategy = promotionStrategy;}public double getFinalPrice() {return promotionStrategy.calculateDiscount(originalPrice);}public void setPromotionStrategy(PromotionStrategy promotionStrategy) {this.promotionStrategy = promotionStrategy;}
}

3.1.4 客户端代码

客户端代码可以根据需要选择不同的促销策略,并计算订单的最终价格。

public class Client {public static void main(String[] args) {double originalPrice = 100.0;// 固定金额折扣PromotionStrategy fixedDiscountStrategy = new FixedDiscountStrategy(10.0);Order order1 = new Order(originalPrice, fixedDiscountStrategy);System.out.println("Fixed Discount: " + order1.getFinalPrice());// 百分比折扣PromotionStrategy percentageDiscountStrategy = new PercentageDiscountStrategy(0.2);Order order2 = new Order(originalPrice, percentageDiscountStrategy);System.out.println("Percentage Discount: " + order2.getFinalPrice());// 无折扣PromotionStrategy noDiscountStrategy = new NoDiscountStrategy();Order order3 = new Order(originalPrice, noDiscountStrategy);System.out.println("No Discount: " + order3.getFinalPrice());// 动态更改策略order1.setPromotionStrategy(percentageDiscountStrategy);System.out.println("Changed to Percentage Discount: " + order1.getFinalPrice());}
}

客户端代码创建不同的策略对象,并将它们传递给 Order 对象,计算最终价格。还可以在运行时动态更改策略。

3.1.5 输出结果

Fixed Discount: 90.0
Percentage Discount: 80.0
No Discount: 100.0
Changed to Percentage Discount: 80.0

3.2 总结

3.2.1 优点

  • 灵活性:可以在运行时动态选择算法。
  • 扩展性:新增策略时,只需实现新的策略类,无需修改现有代码。
  • 代码复用:不同的上下文可以共享相同的策略。

3.2.2 缺点

  • 类的数量增加:每增加一个策略,就需要增加一个类。
  • 客户端需要知道所有策略:客户端需要了解所有可用的策略,并选择合适的策略。

4.命令模式(Command)

命令模式Command)是一种行为设计模式,它将请求封装成一个对象,从而使你能够用不同的请求、队列或者请求日志来参数化其他对象。命令模式也支持可撤销的操作。

在这里插入图片描述

4.1 组成部分

  • 命令对象:封装了一个请求,包括执行该请求所需的所有信息(例如,接收者、方法、参数等)。
  • 接收者:实际执行命令的对象。
  • 调用者:请求的发起者,它将命令对象传递给接收者。
  • 客户端:创建命令对象并将其设置到调用者中。

4.2 示例

假设我们正在开发一个智能家居系统,用户可以通过 遥控器 控制不同的设备(如 风扇 等)。我们可以使用命令模式来实现这个功能。

4.2.1 命令接口

首先,定义一个命令接口 Command,声明一个执行命令的方法 execute

public interface Command {void execute();
}

4.2.2 具体命令实现

接下来,实现不同的命令,例如控制灯的开关和控制风扇的开关。

// 开灯
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}// 关灯
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}// 开风扇
public class FanOnCommand implements Command {private Fan fan;public FanOnCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.turnOn();}
}// 关闭风扇
public class FanOffCommand implements Command {private Fan fan;public FanOffCommand(Fan fan) {this.fan = fan;}@Overridepublic void execute() {fan.turnOff();}
}

LightOnCommandLightOffCommandFanOnCommandFanOffCommand 实现了 Command 接口,分别控制灯和风扇的开关。

4.2.3 接收者

接收者是 实际执行命令的对象,例如灯和风扇。

public class Light {public void turnOn() {System.out.println("Light is on");}public void turnOff() {System.out.println("Light is off");}
}public class Fan {public void turnOn() {System.out.println("Fan is on");}public void turnOff() {System.out.println("Fan is off");}
}

LightFan 是实际执行命令的对象。

4.2.4 调用者

调用者是 请求的发起者,它将命令对象传递给接收者。

public class RemoteControl {private Command onCommand;private Command offCommand;public RemoteControl(Command onCommand, Command offCommand) {this.onCommand = onCommand;this.offCommand = offCommand;}public void pressOnButton() {onCommand.execute();}public void pressOffButton() {offCommand.execute();}
}

RemoteControl 是请求的发起者,它将命令对象传递给接收者并执行命令。

4.2.5 客户端

客户端代码 创建不同的命令对象,并将它们设置到 RemoteControl 中,通过调用 RemoteControl 的方法来执行命令。

public class CommandPatternDemo {public static void main(String[] args) {Light light = new Light();Fan fan = new Fan();Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);Command fanOn = new FanOnCommand(fan);Command fanOff = new FanOffCommand(fan);RemoteControl remoteControl = new RemoteControl(lightOn, lightOff);remoteControl.pressOnButton(); // 输出: Light is onremoteControl.pressOffButton(); // 输出: Light is offremoteControl = new RemoteControl(fanOn, fanOff);remoteControl.pressOnButton(); // 输出: Fan is onremoteControl.pressOffButton(); // 输出: Fan is off}
}

4.2.6 输出结果

Light is on
Light is off
Fan is on
Fan is off

通过这个例子,你可以看到命令模式如何将请求的发送者和接收者解耦,使代码更加灵活和可扩展。

4.3 总结

4.3.1 优点

  • 解耦:命令模式将请求的发送者和接收者解耦,使两者不直接依赖。
  • 扩展性:可以很容易地增加新的命令,而不需要修改现有的代码。
  • 支持撤销操作:命令对象可以存储执行前的状态,从而支持撤销操作。

4.3.2 缺点

  • 类的数量增加:每个命令都需要一个具体的命令类。
  • 复杂性增加:引入了多个对象和接口,可能会使系统变得更复杂。

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

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

相关文章

rocketmq——docker-compose安装

rocketmq安装 创建文件夹,这里我们分别部署namesrv和broker 1、namesrv.conf listenPort98762、broker.conf # 所属集群名字 brokerClusterNameDefaultCluster # broker 名字,注意此处不同的配置文件填写的不一样,如果在 broker-a.propert…

OpenGL ES 文字渲染方式有几种?

在音视频或 OpenGL 开发中,文字渲染是一个高频使用的功能,比如制作一些酷炫的字幕、为视频添加水印、设置特殊字体等等。 实际上 OpenGL 并没有定义渲染文字的方式,所以我们最能想到的办法是:将带有文字的图像上传到纹理,然后进行纹理贴图。 本文分别介绍下在应用层和 C+…

飞牛云fnOS本地部署WordPress个人网站并一键发布公网远程访问

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress 前言 本文旨在详细介绍如何在飞牛云NAS上利用Docker部署WordPress&a…

字符串处理指南:Air780E软件的全新视角

今天我会把 Air780E软件的字符串处理详细解析,指南如下: 1、Lua字符串介绍 关于字符串,Lua提供了一些灵活且强大的功能,一些入门知识如下: 1.1 字符串定义 在Lua中,字符串可以用单引号或双引号"来定…

C/C++语言 多项式加法和乘法

多项式加法和乘法 多项式的加法题目描述输入输出样例步骤代码段全局变量设定新建结点合并链表 完整代码 多项式乘法题目描述输入输出样例代码段计算两多项式结果输入 完整代码 多项式的加法 题目描述 输入输出 样例 步骤 总体思想是用链表来做 ① 我们发现输入样例中&#xf…

第十四章 Spring之假如让你来写AOP——雏形篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…

微信小程序——实现二维码扫描功能(含代码)

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

linux rocky 9.4部署和管理docker harbor私有源

文章目录 Harbor简介安装Harbor技术细节1.安装系统(略),设置主机名和IP2.安装docker3.安装docker-compose4.安装Harbor私有源仓库5 测试登录1.本机登录2.客户端登录Harbor服务器配置docker源1. 下载镜像2.把镜像上传到Harbor私有仓库源3.客户端下载镜像,并且启动容器linux …

【Elasticsearch入门到落地】1、初识Elasticsearch

一、什么是Elasticsearch Elasticsearch(简称ES)是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容。它使用Java编写,基于Apache Lucene来构建索引和提供搜索功能,是一个分布式、可扩展、近实…

【算法一周目】双指针(2)

目录 有效三角形的个数 解题思路 C代码实现 和为s的两个数字 解题思路 C代码实现 三数之和 解题思路 C代码实现 四数之和 解题思路 C代码实现 有效三角形的个数 题目链接:611. 有效三角形的个数题目描述:给定一个包含非负整数的数组nums&…

单体架构 IM 系统之 Server 节点状态化分析

基于 http 短轮询模式的单体架构的 IM 系统见下图,即客户端通过 http 周期性地轮询访问 server 实现消息的即时通讯,也就是我们前面提到的 “信箱模型”。“信箱模型” 虽然实现非常容易,但是消息的实时性不高。 我们在上一篇文章&#xff08…

让AI为你发声!Windows电脑快速部署ChatTTS文本转语音神器

文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 嘿,朋友们!今天我们来聊聊如何在Windows系统上快速搭建ChatTTS,一个超酷的开源文本转语音项目。更棒的是,我们还可以用Cp…

RSTP的配置

RSTP相对于STP在端口角色、端口状态、配置BPDU格式、配置BPDU的处理方式、快速收敛机制、拓扑变更机制和4种保护特性方面的详细改进说明: 端口角色: STP中定义了三种端口角色:根端口(Root Port)、指定端口&#xff0…

elementui el-table中给表头 el-table-column 加一个鼠标移入提示说明

前言 在使用el-table 表格中有些表格的表头需要加入一些提示&#xff0c;鼠标移入则出现提示&#xff0c;非常实用&#xff0c;我是通过el-table中的el-tooltip实现的&#xff0c;以下的效果预览 代码实现 <el-table ref"multipleTable" :data"data"…

ubuntu18.04 安装与卸载NCCL conda环境安装PaddlePaddle

cuda版本11.2 说明PaddlePaddle需要安装NCCL 1、Log in | NVIDIA Developer 登录官网 找到对应版本 官方提供了多种安装方式&#xff0c;本文使用Local installers (x86)本地安装 点击对应的版本下载如&#xff1a; nccl-local-repo-ubuntu1804-2.8.4-cuda11.2_1.0-1_amd6…

机器学习—决定下一步做什么

现在已经看到了很多不同的学习算法&#xff0c;包括线性回归、逻辑回归甚至深度学习或神经网络。 关于如何构建机器学习系统的一些建议 假设你已经实现了正则化线性回归来预测房价&#xff0c;所以你有通常的学习算法的成本函数平方误差加上这个正则化项&#xff0c;但是如果…

【Rust中的项目管理】

Rust中的项目管理 前言Package&#xff0c;Crate&#xff0c;Module &use &#xff0c;Path通过代码示例解释 Crate&#xff0c;Module &#xff0c;use&#xff0c;Path创建一个package&#xff1a;代码组织化skin.rs 中的代码struct & enum 相对路径和绝对路径引用同…

labview用sql server数据库存取数据到一个单元格

最近有一个项目上需要一个庞大的数据量&#xff0c;需要很多列&#xff0c;但是百度查了一下sqi server最多支持1024列&#xff0c;这一限制适用于大多数表类型&#xff0c;包括常规表&#xff0c;临时表和表变量&#xff0c;要注意的是如果超出这一限制可能会导致数据的完整性…

架构篇(04理解架构的演进)

目录 学习前言 一、架构演进 1. 初始阶段的网站架构 2. 应用服务和数据服务分离 3. 使用缓存改善网站性能 4. 使用应用服务器集群改善网站的并发处理能力 5. 数据库读写分离 6. 使用反向代理和CDN加上网站相应 7. 使用分布式文件系统和分布式数据库系统 8. 使用NoSQL和…

Unity学习笔记(4):人物和基本组件

文章目录 前言开发环境新增角色添加组件RigidBody 2D全局项目设置Edit 给地图添加碰撞体 总结 前言 今天不加班&#xff0c;有空闲时间。争取一天学一课&#xff0c;养成习惯 开发环境 Unity 6windows 11vs studio 2022Unity2022.2 最新教程《勇士传说》入门到进阶&#xff…