设计模式1-策略模式全面解析+案例实践+总结

xiaoxiao2021-03-01  10

本文是对面向对象设计模式--策略模式的一个解析,主要分为定义解析、以案例-鸭子游戏对策略模式解析、多案例练习加深对策略模式的理解、最后总结整理知识要点与策略模式的一些优缺点或适用场景。

第一篇:定义解析

策略模式是GoF四人帮整理的《设计模式-可复用面向对象软件基础》一书中23种设计模式中归类为行为型模式中的一种,23种设计模式根据它们的用途分为三大类:5种创建型模式、7种结构型模式、11种行为型模式。

引自GoF四人帮对策略模式的定义与类图:

Strategy(策略模式):定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。

1)一系列算法或者也可以说是一个算法族,代表这些算法具有同一种特性。

如策略模式类图中具体算法实现ConcreteStrategyA、ConcreteStrategyB、ConcreteStrategyC都属于同一个接口Strategy的具体实现。

算法可以理解为能够解决某个问题或完成某个功能的方法,例如实现不同叫声行为的方法。

2)把它们一个个封装起来,蕴含着面向对象设计原则--封装变化。

OO设计原则:找出应用中可能需要变化之处,把它们独立起来,不要和那些不需要变化的代码混在一起。

通过封装变化原则,当应用需要变化的时候,只需要修改已经封装起来会变化的部分,而不会影响到应用的其它部分。提高了应用的弹性与可维护性。

策略模式中的一系列算法,就是应用中会变化的部分被一个个封装起来。如策略模式类图中具体算法实现ConcreteStrategyA、ConcreteStrategyB、ConcreteStrategyC,如果需要对某一个算法如ConcreteStrategyA进行改正,只需要对其一个实现类进行修改即可,不会对其它类产生影响;或者需要添加新的算法实现,只需要新增一个实现即可不会对旧的代码产生影响。

3)使它们可相互替换,蕴含着面向对象设计原则--针对接口编程。

OO设计原则:针对接口编程,而不是针对实现编程。

针对接口编程的真正意思是针对超类型编程。更具体的说变量的声明类型应该是超类型,通常是一个抽象类型或一个接口,如此只要是具体实现此超类型的实现类所产生的对象都可以指定给这个变量;也意味着,声明类时不用理会执行时真正的对象类型。

如策略模式类图中,Context声明类型为超类型Strategy,Context不需要理会执行时具体的对象类型是哪一个;同时,运行时也可以对具体的对象类型进行修改。

 

第二篇:以案例-鸭子游戏对策略模式解析

引自《Head First 设计模式》-- 进入设计模式的世界。

1)原始需求:现有一款游戏,游戏中出现各种鸭子,一边游泳,一边呱呱叫。原始设计:采用面向对象技术,设计一个鸭子(Duck)超类,并让各种鸭子继承此超类。如下图所示:

2)需求变更1:现在我们得让鸭子能够飞。这是公司管理层为了更高的市场份额制定的方案(作为程序员的你不得不对游戏进行升级)。

我们继续使用继承的方式实现此需求,在超类中添加飞行方法(fly),如下图所示:

通过在超类中添加方法,所有的子类都会继承它,改动非常小,确能够实现在所有子类中复用。

3)问题发生了?在一次产品演示会上,有一只橡皮鸭在屏幕上飞来飞去......

橡皮鸭是模型鸭子并不能够飞行,但超类中实现了飞行方法,使得橡皮鸭这个子类同样也具备了飞行的方法,如下图所示:

为了解决这个问题,我们不得不在子类橡皮鸭中重写飞行方法(fly)以覆盖超类中的飞行方法,但是如果又有新的鸭子子类也不能飞行,那不得不对每个不能飞行的鸭子子类进行重写。

总结:使用继承带来的缺点,1.代码在多个子类中复用,2.运行时的行为不易改变(在编译期就已经确定好),3.难以得到子类鸭子的全部行为,4.超类改变牵一发动全身。

4)试着使用接口的方式解决?把飞行行为、叫声行为抽象成接口,能够飞的子类鸭子实现飞行接口,不能够飞行的就不实现飞行接口。如下图所示:

采用接口的方式,使用继承因超类改变而使得所有子类都会受影响的问题得到解决,但又产生了新的问题,每一个子类都不得不编写飞行方法,当子类数量变得很大时, 将会造成大量的重复代码;而且当需要对飞行方法进行很小的修改时,不得不对每一个子类的飞行方法进行修改,这将是另一场灾难。

5)OO原则:封装变化。把鸭子游戏中会变化的部分抽取出来,如鸭子的飞行行为与叫声行为,如下图所示:

这样鸭子类就不需要知道飞行行为、叫声行为的具体实现细节了。

OO原则--封装变化:把会变化的部分抽取出并封装起来,以便以后可以轻易的扩展此部分,而不影响其它部分。这样系统变得更有弹性。

6)OO原则:针对接口编程。利用接口代表每个行为,每个行为有自己不同的实现类。如下图所示:

这样设计后,鸭子类不再负责实现飞行方法fly()和叫声方法quack(),而是由行为类专门负责实现。使得飞行行为、叫声行为不再会绑死在鸭子类中,同时这些行为类也能非常方便的复用到其它地方。

7)OO原则:多用组合,少用继承。现在我们整合鸭子类,将飞行和呱呱叫行为,委托给具体的行为类处理,如下图所示:

使用组合建立的系统具有很大的弹性,且可以运行时改变行为。鸭子游戏重构后如下图所示:

鸭子游戏中的飞行行为、呱呱叫行为其实就是使用的策略模式。如呱呱叫、吱吱叫等就是一系列算法,它们共有的特性都是叫声行为,不同的叫声行为之间可相互替换,它们的变化独立于使用它们的客户鸭子类。

 

第三篇 案例练习,案例引自网络。

案例代码链接详见gitHub:

https://github.com/chentian114/100-dayaction/tree/master/designpattern-1/src/main/java/com/chen/dayaction/designpattern/strategy1

案例1:流量冲值案例,根据客户选择不同的产品,选择相应的冲值渠道进行流量冲值,流量冲值渠道有(麻袋氪、融漫、极信)。

具体实现参考链接 FlowRecharge

案例2:出行方式案例,根据不同天气选择不同的出行方式:晴天选择骑行、阴天选择步行、雨天选择开小车。

具体实现参考链接 GoWay

 

案例3:士兵射击游戏,士兵可以选择不同的枪支进行射击,如步枪、手枪。

具体实现参考链接 SoldierGame:

 

案例4:诸葛亮的三个锦囊妙计,刘备到江东娶孙尚香,三个计策分别在三种不同情况下使用:刚到江东,使用找乔国老开后门计策;结婚后,使用找吴国太开绿灯计策;逃离江东情况下,使用找孙夫人断后计策。

具体实现参考链接 Stratagem:

 

案例5:策略枚举案例,实现输入两个数字与加减操作符获得计算结果。

具体实现参考链接CalcualtorDemo

 

第四篇 总结

三条面向对象设计原则:1、封装变化 2、针对接口编程,而不是实现编程3、多用组全,少用继承。

策略模式:定义一个算法族,一个个封装起来,使它们可相互替换。使用算法的变化独立于使用它的客户。

 

优点:

算法可以自由切换,扩展性良好。

缺点:

策略类数量增多,所有策略类都需要暴露给客户,增加客户的难度。

适用场景:

1、当需要频繁的增加else if或case时,可以考虑使用策略模式减少它们之间的耦合度。

2、多个类只有在算法或行为上稍有不同的场景。

3、算法需要自由切换的场景。

4、需要屏蔽算法规则的场景。

 

 

转载请注明原文地址: https://www.6miu.com/read-3850071.html

最新回复(0)