设计模式学习(七)——《大话设计模式》

文章目录

  • 设计模式学习(七)——《大话设计模式》
    • 工作原理
      • 工作流程示例
    • 工作策略模式的应用场景
      • 策略模式的优点
      • 策略模式的缺点
      • 示例代码(Python)
    • 策略模式UML类图
    • 具体应用和使用场景
        • 支付方式选择
        • 数据压缩工具
        • 表单验证
        • 路由算法
        • 日志记录
        • 折扣计算
    • 策略模式和简单工厂模式的不同点

设计模式学习(七)——《大话设计模式》

策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

这种模式涉及到三个角色:

  • 环境类(Context):持有一个策略类的引用,最终给客户端调用。
  • 抽象策略类(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需实现的接口。
  • 具体策略类(ConcreteStrategy):包装了相关的算法或行为。

工作原理

  • 定义策略接口:首先,定义一个策略接口(Strategy),这个接口声明了算法或行为的方法。

  • 实现具体策略:接着,创建实现策略接口的具体策略类(ConcreteStrategy)。每一个具体策略类封装了一种算法或行为。

  • 创建环境类:然后,创建一个环境类(Context),它包含一个策略对象的引用。环境类提供了一个设置策略对象的方法(通常是构造器或者一个setter方法),以及将任务委托给策略对象的执行方法。

  • 客户端使用环境类:最后,客户端创建一个环境类的实例,并选择一个具体策略类传递给环境类。客户端通过环境类调用算法,而具体的算法则由具体策略类实现。

工作流程示例

假设有一个电商系统,需要根据不同的节日提供不同的打折策略。

定义策略接口:首先定义一个打折策略接口 DiscountStrategy,它有一个方法 applyDiscount。

interface DiscountStrategy {double applyDiscount(double price);
}

实现具体策略:然后实现具体策略类,例如 NoDiscountStrategy(无折扣)、ChristmasDiscountStrategy(圣诞节折扣)等。

class NoDiscountStrategy implements DiscountStrategy {public double applyDiscount(double price) {return price; // 不打折}
}class ChristmasDiscountStrategy implements DiscountStrategy {public double applyDiscount(double price) {return price * 0.9; // 打9折}
}

创建环境类:创建一个环境类 PriceCalculator,它包含一个 DiscountStrategy 的引用。

class PriceCalculator {private DiscountStrategy discountStrategy;public PriceCalculator(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}public double calculatePrice(double price) {return discountStrategy.applyDiscount(price);}}

客户端使用:客户端根据当前节日选择合适的打折策略,并使用 PriceCalculator 计算打折后的价格。

public class Main {public static void main(String[] args) {DiscountStrategy christmasDiscount = new ChristmasDiscountStrategy();PriceCalculator calculator = new PriceCalculator(christmasDiscount);double originalPrice = 100.0;double discountedPrice = calculator.calculatePrice(originalPrice);System.out.println("打折后的价格是:" + discountedPrice);}}

工作策略模式的应用场景

当你想使用对象中的各种不同算法变体,同时希望能在运行时改变对象的行为时。
当你有很多类似的类,但它们在某些行为上有所不同时。
为了避免使用多重条件选择语句。不是使用条件选择来选择所需的行为,而是把这些行为封装在一个个独立的策略类中。

策略模式的优点

  • 策略模式提供了管理相关的算法族的办法。
  • 策略模式可以提供相同行为的不同实现。
  • 使用策略模式可以避免使用多重条件转移语句。
  • 策略模式提供了一种替换继承关系的方法。

策略模式的缺点

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式会在程序中增加许多策略类或者策略对象。

示例代码(Python)

from abc import ABC, abstractmethodclass Strategy(ABC):@abstractmethoddef do_algorithm(self, data):passclass ConcreteStrategyA(Strategy):def do_algorithm(self, data):return sorted(data)class ConcreteStrategyB(Strategy):def do_algorithm(self, data):return reversed(sorted(data))class Context():def __init__(self, strategy: Strategy):self._strategy = strategy@propertydef strategy(self):return self._strategy@strategy.setterdef strategy(self, strategy: Strategy):self._strategy = strategydef do_some_business_logic(self):result = self._strategy.do_algorithm(["a", "b", "c", "d", "e"])print(",".join(result))####客户端代码context = Context(ConcreteStrategyA())
context.do_some_business_logic()context.strategy = ConcreteStrategyB()
context.do_some_business_logic()

策略模式UML类图

          +-------------------+|    Strategy       |+-------------------+| +execute(): void  |+-------------------+^| 实现+------------+-------------+|                          |
+-----------+             +-----------+
| ConcreteStrategyA |             | ConcreteStrategyB |
+-----------+             +-----------+
| +execute()       |             | +execute()       |
+-----------+             +-----------++-------------------+|     Context       |+-------------------+| -strategy: Strategy || +setStrategy(Strategy) || +executeStrategy()  |+-------------------+

trategy(策略接口):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口。Context使用这个接口调用具体策略定义的算法。
ConcreteStrategy(具体策略):Strategy接口的具体实现,每个实现代表了一个算法。
Context(环境类):持有一个策略类的引用,最终给客户端调用。它不决定哪一个算法是正确的,完全由客户端决定。

具体应用和使用场景

支付方式选择

在电商平台或在线支付系统中,用户可以选择多种支付方式(如支付宝、微信支付、银行卡等)。策略模式可以将每种支付方式实现为一个具体的策略类,支付系统的上下文(Context)根据用户的选择动态切换支付策略。

from abc import ABC, abstractmethod# 策略接口
class PaymentStrategy(ABC):@abstractmethoddef pay(self, amount):pass# 具体策略类:支付宝支付
class AlipayPayment(PaymentStrategy):def pay(self, amount):print(f"支付宝支付{amount}元")# 具体策略类:微信支付
class WechatPayment(PaymentStrategy):def pay(self, amount):print(f"微信支付{amount}元")# 环境类
class PaymentContext:def __init__(self, strategy: PaymentStrategy):self._strategy = strategydef execute_payment(self, amount):self._strategy.pay(amount)# 客户端代码
if __name__ == "__main__":context = PaymentContext(AlipayPayment())context.execute_payment(100)context = PaymentContext(WechatPayment())context.execute_payment(50)
数据压缩工具

一个支持多种压缩算法(如ZIP、RAR、7z等)的工具可以使用策略模式来设计。每种压缩算法都作为一个具体策略实现,用户可以根据需要选择不同的压缩策略。

from abc import ABC, abstractmethod
import zipfile
import rarfile# 策略接口
class CompressionStrategy(ABC):@abstractmethoddef compress(self, files, archive):pass# 具体策略类:ZIP压缩
class ZipCompressionStrategy(CompressionStrategy):def compress(self, files, archive):with zipfile.ZipFile(archive, 'w') as zipf:for file in files:zipf.write(file)print(f"{archive} has been created with ZIP compression.")# 具体策略类:RAR压缩
class RarCompressionStrategy(CompressionStrategy):def compress(self, files, archive):with rarfile.RarFile(archive, 'w') as rarf:for file in files:rarf.write(file)print(f"{archive} has been created with RAR compression.")# 环境类
class CompressionContext:def __init__(self, strategy: CompressionStrategy):self._strategy = strategydef set_strategy(self, strategy: CompressionStrategy):self._strategy = strategydef create_archive(self, files, archive):self._strategy.compress(files, archive)# 客户端代码
if __name__ == "__main__":files = ['example.txt', 'example2.txt']context = CompressionContext(ZipCompressionStrategy())context.create_archive(files, 'archive.zip')context.set_strategy(RarCompressionStrategy())context.create_archive(files, 'archive.rar')
表单验证

在Web开发中,表单验证是一个常见需求。不同的字段可能需要不同的验证策略(如邮箱验证、手机号验证、密码强度验证等)。通过策略模式,可以为每种验证需求实现一个具体策略类,从而使验证逻辑更加灵活和可扩展。

from abc import ABC, abstractmethod
import re# 验证策略接口
class ValidationStrategy(ABC):@abstractmethoddef validate(self, value):pass# 具体策略类:邮箱验证
class EmailValidationStrategy(ValidationStrategy):def validate(self, value):if re.match(r"[^@]+@[^@]+\.[^@]+", value):print("邮箱格式正确。")return Trueelse:print("邮箱格式错误。")return False# 具体策略类:手机号验证
class PhoneValidationStrategy(ValidationStrategy):def validate(self, value):if re.match(r"^1[3-9]\d{9}$", value):print("手机号格式正确。")return Trueelse:print("手机号格式错误。")return False# 环境类
class ValidationContext:def __init__(self, strategy: ValidationStrategy):self._strategy = strategydef set_strategy(self, strategy: ValidationStrategy):self._strategy = strategydef validate_field(self, value):return self._strategy.validate(value)# 客户端代码
if __name__ == "__main__":email_validator = ValidationContext(EmailValidationStrategy())phone_validator = ValidationContext(PhoneValidationStrategy())email_validator.validate_field("example@example.com")phone_validator.validate_field("13800000000")
路由算法

在网络设备或软件中,根据不同的网络条件选择最优的路由算法是很常见的需求。例如,可以基于最短路径、最少跳数或最低成本等标准来选择路由。每一种路由算法都可以实现为一个具体的策略类。

from abc import ABC, abstractmethod# 路由策略接口
class RoutingStrategy(ABC):@abstractmethoddef find_route(self, source, destination):pass# 具体策略类:最短路径优先
class ShortestPathStrategy(RoutingStrategy):def find_route(self, source, destination):# 假设的算法实现,实际应用中需要替换为具体的最短路径算法print(f"从{source}{destination}的最短路径已选择。")# 具体策略类:最少跳数优先
class LeastHopsStrategy(RoutingStrategy):def find_route(self, source, destination):# 假设的算法实现,实际应用中需要替换为具体的最少跳数算法print(f"从{source}{destination}的最少跳数路径已选择。")# 环境类
class Router:def __init__(self, strategy: RoutingStrategy):self._strategy = strategydef set_strategy(self, strategy: RoutingStrategy):self._strategy = strategydef route(self, source, destination):self._strategy.find_route(source, destination)# 客户端代码
if __name__ == "__main__":router = Router(ShortestPathStrategy())router.route("A", "B")router.set_strategy(LeastHopsStrategy())router.route("A", "C")
日志记录

在软件系统中,可能需要将日志记录到不同的地方,比如控制台、文件或远程服务器等。通过策略模式,可以为每种日志记录方式实现一个具体策略类,使得日志记录方式可以灵活切换。

from abc import ABC, abstractmethod
import datetime# 日志记录策略接口
class LogStrategy(ABC):@abstractmethoddef log(self, message):pass# 具体策略类:控制台日志记录
class ConsoleLogStrategy(LogStrategy):def log(self, message):print(f"{datetime.datetime.now()}: {message}")# 具体策略类:文件日志记录
class FileLogStrategy(LogStrategy):def __init__(self, file_name):self.file_name = file_namedef log(self, message):with open(self.file_name, 'a') as file:file.write(f"{datetime.datetime.now()}: {message}\n")# 环境类
class Logger:def __init__(self, strategy: LogStrategy):self._strategy = strategydef set_strategy(self, strategy: LogStrategy):self._strategy = strategydef log(self, message):self._strategy.log(message)# 客户端代码
if __name__ == "__main__":logger = Logger(ConsoleLogStrategy())logger.log("这是一条控制台日志信息。")logger.set_strategy(FileLogStrategy("logs.txt"))logger.log("这是一条文件日志信息。")
折扣计算

在销售系统中,根据不同的促销活动(如满减、打折、返现等)计算折扣。每种促销活动都可以实现为一个具体策略类,销售系统根据当前的促销策略来计算最终价格。

from abc import ABC, abstractmethod# 折扣策略接口
class DiscountStrategy(ABC):@abstractmethoddef apply_discount(self, amount):pass# 具体策略类:固定金额折扣
class FixedDiscountStrategy(DiscountStrategy):def __init__(self, discount):self.discount = discountdef apply_discount(self, amount):return max(amount - self.discount, 0)# 具体策略类:百分比折扣
class PercentageDiscountStrategy(DiscountStrategy):def __init__(self, percentage):self.percentage = percentagedef apply_discount(self, amount):return amount * (1 - self.percentage / 100.0)# 环境类
class DiscountContext:def __init__(self, strategy: DiscountStrategy):self._strategy = strategydef set_strategy(self, strategy: DiscountStrategy):self._strategy = strategydef calculate_price(self, amount):return self._strategy.apply_discount(amount)if __name__ == "__main__":# 创建一个DiscountContext对象,初始策略为固定金额折扣10discount_context = DiscountContext(FixedDiscountStrategy(10))# 计算并打印固定金额折扣后的价格print(f"固定金额折扣后价格:{discount_context.calculate_price(100)}")  # 输出应该是90# 更改策略为百分比折扣20%discount_context.set_strategy(PercentageDiscountStrategy(20))# 计算并打印百分比折扣后的价格print(f"百分比折扣后价格:{discount_context.calculate_price(100)}")  # 输出应该是80

策略模式和简单工厂模式的不同点

策略模式(Strategy Pattern)和简单工厂模式(Simple Factory Pattern)是两种常用的设计模式,它们在解决问题的方式和应用场景上有所不同。

以下是它们之间的主要区别:

  • 策略模式
    • 目的:策略模式的目的是定义一系列算法,将它们封装起来,并使它们可以互相替换。策略模式允许算法在不影响客户端的情况下独立于使用它们的客户端变化。
    • 应用场景:当有多种类似的操作或算法,且它们之间仅在实现细节上有所不同时,可以使用策略模式。它允许在运行时选择最适合的算法或操作。
    • 实现方式:通常通过定义一个公共接口来实现,各个策略类实现这个接口,客户端通过持有一个对这个接口的引用来使用不同的策略。
  • 简单工厂模式
    • 目的:简单工厂模式的目的是创建对象。它提供一个创建对象的接口,将对象的创建过程封装起来,客户端不需要知道具体的类名,只需要知道相应的参数。
    • 应用场景:当创建对象的逻辑比较复杂,但是又希望客户端代码与对象创建过程解耦时,可以使用简单工厂模式。它常用于创建相似对象的场景。
    • 实现方式:通过一个工厂类来实现,工厂类有一个静态方法,根据不同的参数返回不同类的实例。客户端只需要调用这个方法并传递相应的参数,无需直接实例化对象。
  • 主要区别
    • 目标不同:策略模式主要用于封装算法族和动态选择算法,而简单工厂模式主要用于创建对象。
    • 应用场景不同:策略模式适用于算法或操作多样性的场景,简单工厂模式适用于创建对象时需要隐藏创建逻辑的场景。
    • 实现方式和侧重点不同:策略模式侧重于定义一系列可互换的算法,并让客户端可以动态选择使用哪一种算法。简单工厂模式侧重于封装对象创建过程,减少客户端与具体类之间的依赖。

:通常通过定义一个公共接口来实现,各个策略类实现这个接口,客户端通过持有一个对这个接口的引用来使用不同的策略。

  • 简单工厂模式
    • 目的:简单工厂模式的目的是创建对象。它提供一个创建对象的接口,将对象的创建过程封装起来,客户端不需要知道具体的类名,只需要知道相应的参数。
    • 应用场景:当创建对象的逻辑比较复杂,但是又希望客户端代码与对象创建过程解耦时,可以使用简单工厂模式。它常用于创建相似对象的场景。
    • 实现方式:通过一个工厂类来实现,工厂类有一个静态方法,根据不同的参数返回不同类的实例。客户端只需要调用这个方法并传递相应的参数,无需直接实例化对象。
  • 主要区别
    • 目标不同:策略模式主要用于封装算法族和动态选择算法,而简单工厂模式主要用于创建对象。
    • 应用场景不同:策略模式适用于算法或操作多样性的场景,简单工厂模式适用于创建对象时需要隐藏创建逻辑的场景。
    • 实现方式和侧重点不同:策略模式侧重于定义一系列可互换的算法,并让客户端可以动态选择使用哪一种算法。简单工厂模式侧重于封装对象创建过程,减少客户端与具体类之间的依赖。

简而言之,策略模式关注于算法和行为的多样性及其可替换性,而简单工厂模式关注于创建具体对象,隐藏创建细节,减少客户端与具体类之间的依赖。

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

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

相关文章

C#语法知识之循环语句

5、循环语句 文章目录 1、while思考1 斐波那契数列思考2 判断一个数是否为质数思考3 找出100以内的质数 2、do...while3、for思考1 找水仙花数思考2 乘法表 1、while 1、作用 让代码重复去执行 2、语法相关 while(bool类型值){//当满足条件时,就会执行while语句…

【GIS教程】ArcGIS做日照分析(附练习数据下载)

我国对住宅日照标准的规定是:冬至日住宅底层日照不少于1小时或大寒日住宅层日照不少于2小时(通常以当地冬至日正午12时的太阳高度角作为依据)。因冬至日太阳高度角最低,照射范围最小,如果冬至日12:00建筑物底层能够接收到阳光,那么…

Python数据可视化库—Bokeh与Altair指南

👽发现宝藏 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在数据科学和数据分析领域,数据可视化是一种强大的工具,可以帮助我们…

Docker - HelloWorld

原文地址,使用效果更佳! Docker - HelloWorld | CoderMast编程桅杆https://www.codermast.com/dev-tools/docker/docker-helloworld.html 开始之前 在学习本小节之前,你必须确保你正确安装了 Docker,正确安装 Docker 是后续学习的…

墨子web3实时周报

蚂蚁集团Web3研发进展与布局 国内Web3赛道的领军企业——蚂蚁集团,凭借其在前沿科技领域的深耕不辍,已在Web3技术研发疆域缔造了卓越战绩。特别是在引领行业革新的关键时刻,集团于今年四月末震撼推出了颠覆性的Web3全套解决方案,…

第十五届蓝桥杯题解-握手

题目大意:有50个人组成的派对,每个人都要与其他所有人进行握手,但其中有7个人之间互相不握手,求握手多少次,a与b握手即b与a握手 思路:规定前7个人互相不握手,两重for循环暴力就好 代码&#x…

java通过maven导入本地jar包的三种方式

一、引入lib下加载(加载过后打包,以后再次使用不用再次导入) 首先创建一个用于创建jar包的项目,并测试能否成功运行 讲项目打包 在需要引入的项目中创建lib目录 并把刚才打包的jar复制进去 通过dependency引入jar包 groupId、art…

读天才与算法:人脑与AI的数学思维笔记05_算法的幻觉

1. 自下而上 1.1. 代码在未来可以自主学习、适应并进行自我改进 1.2. 程序员通过编程教会计算机玩游戏,而计算机却会比教它的人玩得更好,这种输入寡而输出众的事情不大可能实现 1.3. 早在20世纪50年代,计算机科学家们就模拟该过程创造了感…

人工智能论文GPT-3(3):2020.5 Language Models are Few-Shot Learners;架构;训练数据集;开源

2.1 模型与架构 我们使用了与GPT-2相同的模型和架构,包括其中描述的改进初始化、预归一化和可逆分词技术,但有所不同的是,我们在Transformer的各层中使用了交替的密集和局部带状稀疏注意力模式,类似于Sparse Transformer 。为了研…

Flutter 的 showDialog 和 showCupertinoDialog 有什么区别?

我将我的 App 里用的 Flutter 升级到了 3.19,没想到,以前我用 showDialog 和 AlertDialog 组合创建的二次确认框,变得无敌难看了,大幅度增加了整个框的圆角和里面默认按钮的圆角。不得已,我必须修改一下,以…

算法练习|Leetcode189轮转数组 ,Leetcode56合并区间,Leetcode21合并两个有序链表,Leetcode2两数相加,sql总结

目录 一、Leetcode189轮转数组题目描述解题思路方法:切片总结 二、Leetcode56合并区间题目描述解题思路方法:总结 三、Leetcode21合并两个有序链表题目描述解题思路方法:总结 四、Leetcode2两数相加题目描述解题思路方法:总结 sql总结: 一、Leetcode189轮转数组 题目描述 给定…

dfs+剪枝,LeetCode 39. 组合总和

一、题目 1、题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 …

C++|stack-queue-priority_queue(适配器+模拟实现+仿函数)

目录 一、容器适配器 1.1容器适配器概念的介绍 1.2stack和queue的底层结构 1.3deque容器的介绍 1.3.1deque的缺陷及为何选择他作为stack和queue的底层默认实现 二、stack的介绍和使用 2.1stack的介绍 2.2stack的使用 2.3stack的模拟实现 三、queue的介绍和使用 …

NotePad++联动ABAQUS

Abaqus 中脚本运行 1. 命令区kernel Command Line Interface (KCLI) execfile(C:\\temp\second develop\chapter2\pyTest1.py)2. CAE-Run Script File->Run Script 3. Abaqus command Abaqus cae noGUIscript.py(前后处理都可)Abaqus Python scr…

排序算法集合

912. 排序数组 趁着这道题总结下排序方法 1.快速排序 算法描述 1.从数列中挑出一个元素,称为"基准"(pivot), 2.重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基…

Redis的内存淘汰策略(简单版)

以下是常见的内存淘汰策略: 1.LRU(最近最少使用): 这是redis的默认策略,就是最近最少使用的键被淘汰 2.LFU(最不常使用)就是最近最不常使用的键被淘汰 3.Random(随机淘汰&#xff09…

【网站项目】高校毕业论文管理系统小程序

🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板&#xff…

ES主要功能特性和使用场景

ES主要功能特性和使用场景 ES 通常指的是 Elasticsearch,这是一个高度可扩展的开源全文搜索引擎和数据分析平台。Elasticsearch 以其强大的实时搜索、分析和数据可视化能力而闻名,广泛应用于日志分析、应用程序监控、全文检索、商业智能、点击流分析等多…

人工智能论文GPT-3(2):2020.5 Language Models are Few-Shot Learners;微调;少样本Few-Shot (FS)

2 方法Approach 我们的基本预训练方法,包括模型、数据和训练,与GPT-2中描述的过程相似,只是模型规模、数据集规模和多样性,以及训练时长有所扩大,相对简单直接。 我们使用的上下文学习也与GPT-2相似,但在…

SpringCloud系列(8)--将服务提供者Provider注册进Eureka Server

前言:上一章节我们介绍了Eureka服务端的安装与配置,本章节则介绍关于微服务如何入职Eureka Server Eureka架构原理图 1、修改provider-payment8001子模块的pom.xml文件,引入Eureka Clinet的依赖,然后reolad一下,下载依…