设计模式之策略模式

本文深入解析策略模式,探讨如何利用策略模式分离变化与不变部分,提高代码灵活性与扩展性。通过实战案例,展示策略模式在应对频繁需求变更时的优势。

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

前言

作为一个开发者,在工作中最经常遇到也最怕遇到的情况就是产品过来变更需求。一旦产品变更需求,来来回回的调整所带来的心里烦躁不说,有些变更常常会导致代码结构需要大调整才能实现效果。那么要如何应对这种需求变更导致经常大范围调整代码呢?可以考虑考虑策略模式。

策略模式

又称“政策模式”。定义算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
上述的定义引用自《Head First设计模式》是不是感觉不明觉厉。可以这么理解就是找出需求中会变化的与不会变化的内容,将会变化通过统一的接口定义一个算法家族,将需求中会变化的部分与不变的部分分开处理。

结构

看那个干巴巴的定义,我相信还是感觉一脸懵逼,这是什么鬼?我们来看看类图,宏观的看看策略模式的全貌。
在这里插入图片描述
变化部分:通过统一接口IStrategyA,IStrategyB分组来封装变化部分,可以分别理解为一个算法族。
不变部分:通过组合的方式将IStrategyA,IStrategyB两个接口组合进Client中。Client可以不用关心具体的算法内容是什么,直接调用接口方法即可。

实战

需求:假设要做一个模拟鸭子的游戏,鸭子可以飞可以叫。
面对这个需求直观的感受是我们可以写一个Duck超类里面定义一些鸭子的一些行为,然后不同的鸭子都去继承它。如下图:
在这里插入图片描述
到这里貌似这个需求已经完成,但是这时如果产品希望让某些鸭子会飞,你可能会想到这么做:直接在超类Duck里面加入fly()就可以满足:
在这里插入图片描述
但是有没有发现这个时候RuberDuck一个模型鸭也会飞了。这时你肯定会说我只要在RuberDuck中去复写fly(),不就好了。但是这时候如果有几十种鸭子,每种鸭子的飞行行为都不一样,你就需要一一的去复写fly(),这时候就会感觉到心累了。

面对这样子的需求,首先我们可以发现鸭子会有各种飞行方式,会有各种叫声,很明显这将会是一个产品将来会频繁变更的点。根据上面关于策略模式的定义我们可以封装出两个算法族,一个是鸭子的飞行行为FlyBehavior,一个是鸭子的叫声方式QuackBehavior。如图:
在这里插入图片描述
有了鸭子两种行为,那我们现在还差个鸭子自己本身:
在这里插入图片描述
看上图你会发现

  • 在Duck类中加入了“FlyBehavior”和“QuackBehavior”两个接口类型对象。(针对接口口编程)
  • 开放了setFlyBehavior,setQuackBehavior两个接口可以动态改变行为方式。(算法族之间可以相互替换)
  • 在performFly,performQuack中将行为委托给flyBehavior,quackBehavior两个引用对象,也不用关心是怎么飞,怎么叫的。

如此鸭子的行为与鸭子本身就解耦了,不管后续是新增火箭飞行,还是新增吱吱声等等各种行为,我们都只要实现FlyBehavior,QuackBehavior来新增行为即可满足需求,不需要调整任何鸭子的代码。假设MallaerDuck想在运行时修改飞行方式,可以直接通过setFlyBehavior动态修改行为,实现“运行时动态改变行为”。

OO设计原则

细心的同学可能就会发现上面的设计中遵守了好多的设计原则。分别如下:

  1. 封装变化:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  2. 多用组合,少用继承:使用组合建立系统可以有很大的弹性,同时还可以做到“运行时动态改变行为”,只要组合的行为对象符合正确的接口标准即可。
  3. 针对接口编程,不针对实现编程:使用接口我们可以充分使用多态特性,提升框架的可扩展性。框架不需要关心具体的实现,只要符合接口标准就好,后续新增新的实现不需要调整框架,但框架却可以拥有新的实现能力。

下面我们来看看上述的例子是如何遵守设计原则的:

  • 先从宏观的角度上,看我们将变化部分单独抽离出来遵守的是封装变化原则。
  • 从鸭子的设计上看,我们在鸭子组合了鸭子的各种行为遵守的是多用组合,少用继承。
  • 从鸭子组合方式上看,鸭子中组合的是FlyBehavior,QuackBehavior两个接口行为,而不是直接组合了具体的FlyWithWing,鸭子只管调用接口的方法,而不需要关心我这里调用的是哪个具体的实现类,这里遵守的是针对接口编程,不针对实现编程。

使用场景

当有如下场景的时候可以考虑使用策略模式:

  • 当一个类定义了多种可变化的行为,并且这个类的操作中使用了很多的if/else, 或者switch/case等各种条件语句。那么就可以将相关的条件分支抽象到各自的策略算法中去,用策略算法来代替条件语句。
  • 客户不需要关心具体的行为内容,那么可以使用策略模式封装避免暴漏复杂的行为。
  • 客户需要使用一个算法不同变体的时候可以考虑用策略模式。
  • 几个相关的类只是具体的行为不一样,其他内容是一样的情况。“策略”提供了将多个行为分别设计成一个行为一个类,并且在客户眼里这些行为可以相互替换。

优缺点

优点:
  1. 可以消除一些条件判断语句。
  2. 让客户动态变化行为:同一算法下的行为可以相互替换。
  3. 提供一种替换继承的方法:通过组合来增加行为,而不是通过继承的方式来增加行为。
  4. 让客户与策略解耦:策略可以无限扩展,而不会影响到客户
缺点:
  1. 增加了代码中类的数量:毕竟每个策略都是一个类

总结

总而言之,策略模式可以做到将变化与不变的部分剥离开,减少代码之间的耦合,面对扩展的能力更强。在平常的开发过程中可以根据使用场景,如何有符合的时机就可以多进行实践,运用过程中可不能忘了这当中的弊端哦。

个人公众号:基石分享社

欢迎关注我的公众号,该公众号会持续输出Android开发过程中的各种基础知识的文章,共同学习成长。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值