您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

一文搞懂策略设计模式

时间:2023-05-22 12:52:53  来源:51CTO  作者:张哲刚

作者丨Ashutosh Krishna

译者丨张哲刚

审校丨重楼

策略设计模式是一种行为设计模式。利用它,你可以通过将对象封装到不同的策略中,进而动态地更改对象的行为。

这种模式可以使对象在运行时能够从多个算法和行为中进行选择,而不限于仅仅静态地选择单个算法和行为。

策略设计模式是基于组合而不是继承的原则。它定义了一系列算法,封装了每个算法,它们在运行时可以互相转换。策略设计模式的核心思想是将算法与主对象分开。它允许对象将算法的行为委托给所设计的众多策略中的一个。

一言而蔽之,策略设计模式提供了一种方法,这种方法可以将对象的行为提取到可以在运行时切换出入的单独类中。从而使对象具有更好的灵活性和重用性,因为这种模式可以轻易地添加或修改不同的策略,而无需更改对象的核心代码。

一、使用策略设计模式的好处

使用策略设计模式有很多便利之处,具体如下:

1、更好的代码灵活性:通过将对象的行为封装到不同的策略中,使得代码更加灵活且更易于修改。

2、更好的代码可重用性:由于这些策略是可封装以及可以互换的,所以它们可以在不同的对象和项目中重复使用。

3、促使更好的编码实践:策略设计模式可以促使良好的编码实践,养成良好的编码习惯,例如关注点分离以及代码复杂性的降低。

4、简化测试:策略设计模式通过将算法和行为与对象分离,从而使测试得到简化。

二、策略设计模式的实例

策略设计模式可以应用于各种场景,典型的例子如下:

1、排序算法:可以将不同的排序算法封装到单独的策略中,并发送给需要排序的对象。

2、验证规则:可以将不同的验证规则封装到单独的策略中,并发送给需要验证的对象。

3、文本格式:可以将不同的文本格式设置策略封装到单独的策略中,并发送给需要格式化的对象。

4、数据库访问:可以将不同的数据库访问策略封装到单独的策略中,并发送给需要从不同的数据源访问数据的对象。

5、支付策略:可以将不同的支付方式封装到单独的策略中,并发送给需要处理支付的对象。

三、了解策略设计模式

策略设计模式是面向对象的编程领域里一个非常卓越的模式。它提供了一种灵活的方法来封装和交换对象在运行时的行为,从而使代码更具适应性且更易于维护。

在本节中,我们将更深入地探讨策略设计模式,研究其定义、组件及其工作原理。

1.策略设计模式的组成部分

策略设计模式主要包括三项重要组件:

  • 上下文:策略设计模式所包含的策略行为委托对象。上下文负责维护对策略对象的引用,并通过公共接口与其进行交互。
  • 策略接口:此接口定义所有策略的行为。策略通过此接口来实现其定义的各种行为。
  • 具体策略:实现策略接口的类。每个策略都封装了一个特定的行为,上下文可以在运行时切换到该行为。

2.策略设计模式的工作原理

策略设计模式的工作原理,是将对象的行为与对象本身分开。行为封装到不同的策略中,每个策略都有自己特定的行为实施。

上下文维护对策略对象的引用,并通过公共接口与其进行交互。在运行进程中,上下文可以将当前策略与另外的策略进行交换,从而有效达到更改对象行为的目的。

3.策略设计模式的实际应用举例

音乐流媒体服务是策略设计模式的一个应用实例。这项服务里,不同的订阅层次有其各自不同的定价模型。

针对每个订阅层次,可以用不同的定价策略来封装其单独的价格体系。该服务的计费系统会将定价计算这一行为事项委托给当前订阅层次对应的策略,从而可以轻松修改和扩展价格体系。

支付策略是另外一个应用实例。不同的支付方式可以封装成单独的策略,每种策略都具有它自身单独的处理逻辑。

购物车应用程序可以使用策略设计模式将信用卡、PayPal和加密货币支付方法封装到单独策略中,它们可以在运行时交换。应用程序的支付处理系统将支付方式委托给当前制定的策略,从而可以轻松修改和扩展支付方式。

四、如何实现策略设计模式

在本节中,我们将讨论如何实现策略设计模式。我们将从一个不符合策略设计模式的代码示例开始,找到和研究它存在的问题。然后,我们再重构代码,来演示如何实现策略设计模式。

要在JAVA中实现策略设计模式,需要执行以下步骤:

  • 确定需要封装的算法或行为,并使其可互换。
  • 定义一个表示行为的接口,使用单一方法签名来接收所有必需的参数。
  • 实施一个具体类,用来提供接口中所定义行为的特定实现。
  • 定义一个上下文类,该上下文类保持对接口的引用并在需要时调用其方法。
  • 修改上下文类,以允许动态交换在运行时得以具体实现。

1.代码示例

我们来看以下代码:

packagewithoutstrategy;publicclassPaymentProcessor{
   
    privatePaymentTypepaymentType;
  
    publicvoidprocessPayment(doubleamount){
      
 
    if(paymentType==PaymentType.CREDIT_CARD){
           
       System.out.println("Processing
credit card payment of amount "+amount);
      
 
    }elseif(paymentType==PaymentType.DEBIT_CARD){
           
        System.out.println("Processing
debit card payment of amount "+amount);
       
      }elseif(paymentType==PaymentType.PAYPAL){
          
          System.out.println("Processing
PayPal payment of amount "+amount);
       
      }else{
           thrownewIllegalArgumentException("Invalid
payment type");
      
  }
  
  }
  
    publicvoidsetPaymentType(PaymentTypepaymentType){
       
      this.paymentType=paymentType;}}enumPaymentType{
   
       CREDIT_CARD,
   
       DEBIT_CARD,
   
       PAYPAL}

支付处理器.java

在此代码中,支付处理器类具有一个用来接受付款金额并处理付款的方法。付款类型是使用“设置付款类型”方法设置并设置“付款类型”字段。然后,该方法检查其值并处理相应的付款。

此代码的问题在于它违反了开-闭(开放封闭)原则,该原则指明类应该面向扩展开放,但必须面向修改封闭。而在此代码中,如果想要添加新的付款类型,则必须修改方法,这就违反了开-闭原则。

该支付处理器类通过使用条件语句来确定付款类型,然后相应地对其进行处理,从而违反了策略模式。随着付款类型数量的增加,这种方法很快就会变得难以管理和不够灵活。

要解决这个问题,可以使用策略设计模式。首先,为所有支付策略定义一个通用接口,在本例中为支付策略接口:

package withstrategy;

public interface PaymentStrategy {
    void processPayment(double amount);
}

支付策略.java

然后,你可以为每种付款类型定义其支付策略接口的具体实现。例如下面这些类:

  • 信用卡支付策略;
  • 借记卡支付策略;
  • 贝宝支付策略。
package withstrategy;

public class CreditCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of amount " + amount);
    }
}

信用卡支付策略.java

package withstrategy;

public class DebitCardPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing debit card payment of amount " + amount);
    }
}

借记卡支付策略.java

package withstrategy;

public class PaypalPaymentStrategy implements PaymentStrategy {
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of amount " + amount);
    }
}

贝宝支付策略.java

最后,更新支付处理器类用以从构造器中获取支付策略对象,用于处理付款流程:

package withstrategy;

public class PaymentProcessor {
    private PaymentStrategy paymentStrategy;

    public PaymentProcessor(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void processPayment(double amount) {
        paymentStrategy.processPayment(amount);
    }
}

支付处理器.java

这一实现遵循开闭原则和策略模式,在其中你可以通过创建支付策略接口的新实现来添加新的支付类型,而并不需要修改现有代码。

2.实施策略设计模式的最佳方案

下面是实施策略设计模式时,要力争记牢的一些最佳方案:

  • 保持界面简洁,专注于单一职责。
  • 将任何有状态的行为封装在具体策略类中,而不是在上下文类中。
  • 使用依赖关系注入将具体策略传达给上下文类,而不是直接在上下文类中创建它。
  • 使用枚举或工厂类为创建和管理具体策略对象提供集中位置。

五、策略设计模式的实际应用

策略设计模式已经广泛用于各种实际应用。Java集合框架就是一个鲜明的例子。集合框架提供了一组接口和类来表示对象的集合,例如列表、集和映射。依据集合的具体行为,该框架允许将不同的策略应用于集合。

例如,集合框架包含一个名为“分类”的方法,用于对集合进行排序。该方法将比较器对象作为参数,负责比较集合中的对象。比较器接口定义了用于比较两个对象的策略,“分类”方法使用此策略对集合进行排序。

此外,集合框架还包括迭代器接口,该接口定义了访问集合元素的策略。迭代器允许用户遍历集合,而不会公开其内部结构,该结构可能会随时间而变化。通过使用迭代器接口,用户可以在访问集合元素的不同策略之间切换。

六、总结

在本教程中,我们探讨了策略设计模式及其在Java中的实现。我们已经了解了如何使用策略模式将对象的行为与其实现分开,从而使代码具备更大的灵活性和可维护性。

我们讨论了策略设计模式的组件,包括上下文、策略接口和具体策略。我们还提供了一个示例,用以说明如何使用该模式来实现支付系统的灵活性,可以在单个界面实现多种支付选项。

通过将对象的行为与其实现分离,策略模式提供了足够的灵活性,更能够适应日新月异不断变化的实际需求。

译者介绍:

张哲刚,51CTO社区编辑,系统运维工程师,国内较早一批硬件评测及互联网从业者,曾入职阿里巴巴。

原文链接:https://www.freecodecamp.org/news/a-beginners-guide-to-the-strategy-design-pattern/



Tags:设计   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
AI+数字人成为市场关注焦点,大屏AI数字人助力展厅设计创意升级
随着各行业产业的数字化转型加速,人工智能时代的到来,展馆展厅行业也步入数字时代,各式的展馆展厅设计在融合了全息投影、虚拟现实、数字沙盘、互动投影、互动桌面等多种技术后...【详细内容】
2024-04-09  Search: 设计  点击:(4)  评论:(0)  加入收藏
微信表情包更新:原创设计师带来全新风格!
随着社交网络的不断发展,表情包已经成为了人们日常沟通中不可或缺的一部分。微信作为中国最受欢迎的即时通讯工具之一,其表情包更是广受欢迎,为用户提供了丰富多彩的表情选择。...【详细内容】
2024-04-08  Search: 设计  点击:(9)  评论:(0)  加入收藏
京东小程序数据中心架构设计与最佳实践
一、京东小程序是什么京东小程序平台能够提供开放、安全的产品,成为品牌开发者链接京东内部核心产品的桥梁,致力于服务每一个信任我们的外部开发者,为不同开发能力的品牌商家提...【详细内容】
2024-03-27  Search: 设计  点击:(10)  评论:(0)  加入收藏
浅析站在seo优化角度考虑网站导航设计
作为网站设计的重要一环,网站导航的设计对于SEO优化起着至关重要的作用。一个良好的网站导航设计不仅可以提高用户体验,还能有效提升搜索引擎的排名。本文将从SEO优化角度,为您...【详细内容】
2024-03-27  Search: 设计  点击:(7)  评论:(0)  加入收藏
苹果重新设计 App Store 购买记录页面:让你的每笔消费清清楚楚
IT之家 3 月 21 日消息,网友 Matt Birchler 近日在 Mastodon 发布动态简讯,表示苹果近期悄然调整了 App Store 应用商城购买历史记录页面,让用户更清晰地了解已购买应用、订阅...【详细内容】
2024-03-21  Search: 设计  点击:(20)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13  Search: 设计  点击:(6)  评论:(0)  加入收藏
前端不存在了?盲测64%的人更喜欢GPT-4V的设计,杨笛一等团队新作
3 月 9 日央视的一档节目上,百度创始人、董事长兼 CEO 李彦宏指出,以后不会存在「程序员」这种职业了,因为只要会说话,人人都会具备程序员的能力。「未来的编程语言只会剩下两种...【详细内容】
2024-03-11  Search: 设计  点击:(9)  评论:(0)  加入收藏
Linux发行版 Ubuntu 迎更新 界面设计灵感来自 Windows 11
近日,一位第三方开发者推出了一款名为“Wubuntu”的特殊Linux发行版。这款系统源自主流的Ubuntu版本,但在界面设计上却借鉴了微软最新的Windows 11风格,甚至在其中融入了微软标...【详细内容】
2024-02-27  Search: 设计  点击:(43)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  Search: 设计  点击:(36)  评论:(0)  加入收藏
海报设计软件推荐:从初学者到专业设计师必备!
龙年新年即将到来,你是否也在为新年海报的设计而犯愁呢?毕竟大家都期待着以焕然一新的海报,迎接新年的到来。不过别担心,现在的海报制作软件可谓是方便又实用,让你能轻松设计出令...【详细内容】
2024-01-26  Search: 设计  点击:(79)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条