设计模式系列(三) —— 策略模式

本文介绍了策略模式的概念、动机、结构及应用场景。策略模式属于对象行为模式,通过定义算法接口,允许客户程序在处理同一任务时灵活地切换不同的策略,从而得到不同的结果。文章详细解释了如何避免硬编码带来的问题,并通过具体例子说明了策略模式的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

策略模式属于对象行为模式,策略模式的目的是客户程序在处理同一个任务时,能够灵活的切换不同的策略,得到不同的结果。

动机与结构

硬编码的后果

想象一下,如果我们将所有的策略都硬编码进客户程序中,会产生什么后果呢,GoF总结了一下三个后果:

  1. 使得客户程序的代码变得十分复杂,难以维护
  2. 不同的时候,客户程序通常需要不同的算法,当我们不使用其中的一些算法时,他们本不应该出现在我们面前。
  3. 添加新的算法变得十分的困难

避免硬编码

上文叙述了硬编码的诸多不足,我们如何避免呢。
假设,现在有一个类(A)负责维护和更新文档程序中文本的显示。避免硬编码的方法为,A 类自身不负责显示的实际策略。而是调用另外一个实现了显示策略的类(B)的方法。这样我们就做到了策略和客户程序代码的分离。解决了硬编码的第一个问题。如果这时候,需要添加另外一种显示策略,我们应该怎么做呢。显然,我们应该再编写一个类(C)负责新的显示策略。在编写客户程序时,可以选择是使用B还是C来负责显示的策略。如果客户程序需要在运行时,切换显示策略呢。这时就需要运行时多态了。所以,我们应该抽象出B和C的接口,形成一个抽象的类S,B和C实现S的接口,这样在运行时,就可以随时切换显示的策略了。
总结一下,策略模式的类图就展示在了我们面前。

class_structure

使用时机

  • 许多目的相同,但是行为相异的相关类。
  • 需要使用一个算法的不同变体。
  • 算法使用了客户不应该知道的数据。使用策略模式,可以避免暴露于算法相关的数据结构。
  • 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。

工作方法

组件

  • Strategy: 定义算法的接口供Context调用
  • ConcreteStrategy: 实现Strategy接口的类
  • Context: 维护对一个Strategy的引用,可以定义接口让Strategy有能力来访问他的数据

协作

  • Strategy 与 Context 互相作用以实现特定的算法。算法调用时,Context 传递给 Strategy 必要的数据,或者自身的引用,以供算法正常工作。
  • Context 转发客户的请求给他的 Strategy。 这样客户只和 Context 交互,就可以执行指定的算法并在必要时更换。

优缺点

优点

  • 继承结构有助于抽取出不同算法的公共之处
  • 算法独立封装于 Strategy 而不是在 Context 中使用继承机制,防止了硬编码的出现,更加灵活,易于扩展。
  • 消除了 Context 或者 客户程序中的一些条件语句。所以过多的条件语句提醒着我们试试策略模式
  • 客户可以灵活选择算法

缺点

  • 客户必须了解所有的策略,才能选择最优的。所以可能不得不向客户暴露策略的具体实现。所以仅当各个策略的差异与客户程序有关时才使用此模式
  • Context 和 Strategy 直接的通信开销有时是不必要的。如果出现很多传递的信息没有被使用的情况,就应该考虑两者之间更紧密的耦合。
  • 增加了对象的数目。可以通过将策略设计为无状态来减少这方面的影响。详见Flyweight模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值