行为型设计模式之策略模式:
一、含义
策略模式是一种比较简单的模式,也叫做政策模式,其定义如下:
定义一组算法(可抽象出接口),将每个算法都封装起来,并且使它们之间可以互换(定义一个类实现封装与算法切换)
二、代码说明
1.主要有两个角色
1)Context封装角色
它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略,算法的直接访问,封装可能存在的变化。
2)策略角色
该类含有具体的算法
2.在用C实现过程中也是参考这种思想,以压缩,解压算法举例,具体实现如下:
1)策略模式使用场景:
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : StrategyPatternUsage.c 5 * Description : 策略模式的使用 6 7 book@book-desktop:/work/projects/test/DesignPatterns/StrategyPattern$ gcc -o StrategyPatternUsage GzipAlgorithm.c ZipAlgorithm.c StrategyPattern.c StrategyPatternUsage.c 8 book@book-desktop:/work/projects/test/DesignPatterns/StrategyPattern$ ./StrategyPatternUsage 9 -----------------执行算法----------------10 c:\Hello--->d:\Hello.zip ZIP压缩成功!11 c:\Hello.zip--->d:\Hello ZIP解压成功!12 *****************替换算法****************13 c:\Hello--->d:\Hello.gzip GZIP压缩成功!14 c:\Hello.gzip--->d:\Hello GZIP解压成功!15 16 * Created : 2017.07.19.17 * Author : Yu Weifeng18 * Function List : 19 * Last Modified : 20 * History : 21 ******************************************************************************/22 #include"stdio.h"23 #include"malloc.h"24 #include"stdlib.h"25 #include"string.h"26 #include"StrategyPattern.h"27 28 29 30 31 /*****************************************************************************32 -Fuction : main33 -Description : 34 -Input : 35 -Output : 36 -Return : 37 * Modify Date Version Author Modification38 * -----------------------------------------------39 * 2017/07/19 V1.0.0 Yu Weifeng Created40 ******************************************************************************/41 int main(int argc,char **argv)42 {43 T_Algorithm tAlgorithm=newZipAlgorithm;44 printf("-----------------执行算法----------------\r\n");45 g_tContext.SetAlgorithm(&tAlgorithm);46 g_tContext.Compress("c:\\Hello","d:\\Hello.zip");47 g_tContext.Uncompress("c:\\Hello.zip","d:\\Hello");48 49 printf("*****************替换算法****************\r\n");50 tAlgorithm=(T_Algorithm)newGzipAlgorithm;51 g_tContext.SetAlgorithm(&tAlgorithm);52 g_tContext.Compress("c:\\Hello","d:\\Hello.gzip");53 g_tContext.Uncompress("c:\\Hello.gzip","d:\\Hello");54 55 56 return 0;57 }
2)被调用者:
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : StrategyPattern.c 5 * Description : 策略模式 6 本文件是环境(上下文)角色(封装算法) 7 以压缩,解压算法举例 8 9 * Created : 2017.07.19.10 * Author : Yu Weifeng11 * Function List : 12 * Last Modified : 13 * History : 14 ******************************************************************************/15 #include"stdio.h"16 #include"malloc.h"17 #include"stdlib.h"18 #include"string.h"19 #include"StrategyPattern.h"20 21 static void SetAlgorithm(T_Algorithm *i_ptAlgorithm);22 static int Compress(char *i_strSource,char *i_strDestination);23 static int Uncompress(char *i_strSource,char *i_strDestination);24 static T_Algorithm g_tAlgorithm;25 26 const T_Context g_tContext={27 .SetAlgorithm =SetAlgorithm,28 .Compress =Compress,29 .Uncompress =Uncompress,30 };31 /*****************************************************************************32 -Fuction : SetAlgorithm33 -Description : 公有函数34 -Input : 35 -Output : 36 -Return : 37 * Modify Date Version Author Modification38 * -----------------------------------------------39 * 2017/07/19 V1.0.0 Yu Weifeng Created40 ******************************************************************************/41 static void SetAlgorithm(T_Algorithm *i_ptAlgorithm)42 {43 memcpy(&g_tAlgorithm,i_ptAlgorithm,sizeof(T_Algorithm));44 }45 46 /*****************************************************************************47 -Fuction : Compress48 -Description : 公有函数49 -Input : 50 -Output : 51 -Return : 52 * Modify Date Version Author Modification53 * -----------------------------------------------54 * 2017/07/19 V1.0.0 Yu Weifeng Created55 ******************************************************************************/56 static int Compress(char *i_strSource,char *i_strDestination)57 {58 return g_tAlgorithm.Compress(i_strSource,i_strDestination);59 }60 61 /*****************************************************************************62 -Fuction : Uncompress63 -Description : 公有函数64 -Input : 65 -Output : 66 -Return : 67 * Modify Date Version Author Modification68 * -----------------------------------------------69 * 2017/07/19 V1.0.0 Yu Weifeng Created70 ******************************************************************************/71 static int Uncompress(char *i_strSource,char *i_strDestination)72 {73 return g_tAlgorithm.Uncompress(i_strSource,i_strDestination);74 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : StrategyPattern.h 5 * Description : 策略模式 6 7 * Created : 2017.07.19. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/13 #ifndef STRATEGY_PATTERN_H14 #define STRATEGY_PATTERN_H15 16 typedef struct Algorithm17 {18 int (*Compress)(char *i_strSource,char *i_strDestination);19 int (*Uncompress)(char *i_strSource,char *i_strDestination);20 }T_Algorithm;21 22 typedef struct Context23 {24 void (*SetAlgorithm)(T_Algorithm *i_ptAlgorithm);25 int (*Compress)(char *i_strSource,char *i_strDestination);26 int (*Uncompress)(char *i_strSource,char *i_strDestination);27 }T_Context;28 29 //环境角色一般一个就够了,30 //如果对执行效率有要求,需要并发时,则可不使用单例31 extern const T_Context g_tContext;32 33 34 int GzipCompress(char *i_strSource,char *i_strDestination);35 int GzipUncompress(char *i_strSource,char *i_strDestination);36 #define newGzipAlgorithm {GzipCompress,GzipUncompress}37 38 int ZipCompress(char *i_strSource,char *i_strDestination);39 int ZipUncompress(char *i_strSource,char *i_strDestination);40 #define newZipAlgorithm {ZipCompress,ZipUncompress}41 42 43 #endif
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ZipAlgorithm.c 5 * Description : ZIP相关算法 6 本文件是算法的具体实现类 7 * Created : 2017.07.19. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/13 #include"stdio.h"14 #include"malloc.h"15 #include"stdlib.h"16 #include"string.h"17 #include"StrategyPattern.h"18 19 /*****************************************************************************20 -Fuction : ZipCompress21 -Description : 公有函数22 -Input : 23 -Output : 24 -Return : 25 * Modify Date Version Author Modification26 * -----------------------------------------------27 * 2017/07/19 V1.0.0 Yu Weifeng Created28 ******************************************************************************/29 int ZipCompress(char *i_strSource,char *i_strDestination)30 {31 printf("%s--->%s ZIP压缩成功!\r\n",i_strSource,i_strDestination);32 return 0;33 }34 35 /*****************************************************************************36 -Fuction : ZipUncompress37 -Description : 公有函数38 -Input : 39 -Output : 40 -Return : 41 * Modify Date Version Author Modification42 * -----------------------------------------------43 * 2017/07/19 V1.0.0 Yu Weifeng Created44 ******************************************************************************/45 int ZipUncompress(char *i_strSource,char *i_strDestination)46 {47 printf("%s--->%s ZIP解压成功!\r\n",i_strSource,i_strDestination);48 return 0; 49 }
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : GzipAlgorithm.c 5 * Description : GZIP相关算法 6 本文件是算法的具体实现类 7 * Created : 2017.07.19. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/13 #include"stdio.h"14 #include"malloc.h"15 #include"stdlib.h"16 #include"string.h"17 #include"StrategyPattern.h"18 19 /*****************************************************************************20 -Fuction : GzipCompress21 -Description : 公有函数22 -Input : 23 -Output : 24 -Return : 25 * Modify Date Version Author Modification26 * -----------------------------------------------27 * 2017/07/19 V1.0.0 Yu Weifeng Created28 ******************************************************************************/29 int GzipCompress(char *i_strSource,char *i_strDestination)30 {31 printf("%s--->%s GZIP压缩成功!\r\n",i_strSource,i_strDestination);32 return 0;33 }34 35 /*****************************************************************************36 -Fuction : GzipUncompress37 -Description : 公有函数38 -Input : 39 -Output : 40 -Return : 41 * Modify Date Version Author Modification42 * -----------------------------------------------43 * 2017/07/19 V1.0.0 Yu Weifeng Created44 ******************************************************************************/45 int GzipUncompress(char *i_strSource,char *i_strDestination)46 {47 printf("%s--->%s GZIP解压成功!\r\n",i_strSource,i_strDestination);48 return 0; 49 }
3)执行结果:
book@book-desktop:/work/projects/test/DesignPatterns/StrategyPattern$ gcc -o StrategyPatternUsage GzipAlgorithm.c ZipAlgorithm.c StrategyPattern.c StrategyPatternUsage.c
book@book-desktop:/work/projects/test/DesignPatterns/StrategyPattern$ ./StrategyPatternUsage
-----------------执行算法----------------
c:\Hello--->d:\Hello.zip ZIP压缩成功!
c:\Hello.zip--->d:\Hello ZIP解压成功!
*****************替换算法****************
c:\Hello--->d:\Hello.gzip GZIP压缩成功!
c:\Hello.gzip--->d:\Hello GZIP解压成功!
4)详细代码:
https://github.com/fengweiyu/DesignThinking/tree/master/DesignPatterns/BehavioralDesignPatterns/StrategyPattern
三、使用场景
1.多个类只有在算法或行为上稍有不同的场景
2.算法需要自由切换的场景
例如,算法的选择是由使用者决定的,或者算法始终在进化(变化)
3.需要屏蔽算法规则的场景
很多算法不需要知道内部实现,传递相关参数进来,反馈运算结果即可
四、优点
1.算法可以自由切换
这时策略模式本身定义的,只要实现抽象策略,它就成为策略家族的一个成员,通过封装角色对其进行封装,封装角色提供传入接口就可以实现算法自由切换
2.避免使用多重条件判断
使用策略模式,可以由其他模块决定采用何种策略,策略家族对外提供的访问接口就是封装类,简化了操作,同时避免了条件语句判断。
3.扩展性良好
只要实现接口就可以增加一个策略,其他都不用修改。
五、缺点
1.策略类数量增多
每一个策略都是一个类,复用的可能性很小,类数量增多
2.所有的策略类都需要对外暴露
上层模块必须知道有哪些策略,然后才能决定使用哪一个策略,这与迪米特原则是相违背的(只想使用一个策略,并不需要了解这个策略),但幸运的是,我们可以使用其他模式来修正这个缺陷,如工厂方法模式、代理模式或享元模式。
因此使用策略模式时需注意:
如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露的问题,否则日后维护很难进行。一般通过工厂方法模式来实现策略类的声明。
六、与其他模式的区别
1、策略模式与代理模式的区别:
差别就是策略模式的封装角色和被封装的策略类不用实现同一个接口,如果是同一个接口那就称为了代理模式。
2、策略模式与命令模式的区别:
1).关注点不同
I、策略模式关注的是算法的完整性、封装性,以保证算法可以自由切换。
II、命令模式则关注的是解耦问题,如何让请求者(调用者)和接收者(执行者)解耦是它需要首先解决的,解耦的要求就是把请求的内容封装为一个个的命令(由接收者执行)。
2).角色功能不同
I、策略模式中的具体算法是负责一个完整算法逻辑,它是一个不可拆分的原子业务单元,一旦变更就是对算法整体的变更。
II、命令模式中的接收者对命令负责,而与请求者(调用者)无关。命令模式中的接收者只要符合六大设计原则,完全不用关心它是否完成了一个具体逻辑。
3),使用场景不同
I、策略模式适用于算法要求变换的场景
II、命令模式适用于解耦两个有紧耦合关系的对象场景或者多命令多撤销的场景
3、策略模式与状态模式的区别:
两个类图非常相似,都是通过context类封装一个具体的行为,都提供了一个封装的方法,是高扩展性的设计模式。
但根据两者定义还是有明显区别的:
策略模式封装的是不同的算法,算法之间没有交互,以达到算法可以自由切换的目的;
而状态模式封装的是不同的状态,以达到状态切换 行为随之发生改变的目的(状态切换一般由环境角色与具体的状态协作完成)。
1)环境角色的职责不同
两者都有一个叫做Context环境角色的类,但是两者的区别很大:
I、策略模式的环境角色只是一个委托作用,负责算法的替换
II、状态模式模式的环境角色不仅仅是委托行为,它还具有登记状态变化的功能,与具体的状态类协作,共同完成状态切换行为随之切换的任务
2)解决问题的重点不同
I、策略模式旨在解决内部算法如何改变的问题,也就是将内部算法的改变对外界的影响降低到最小,它保证的是算法可以自由切换
II、状态模式旨在解决内在状态的改变而引起行为改变的问题,它的出发点是事物的状态,封装状态而暴露行为
3)解决问题的方法不同
I、策略模式只是确保算法可以自由切换,但是什么时候用什么算法它决定不了
II、状态模式对外暴露的是行为,状态的变化一般是由环境角色和具体状态共同完成的。
4)应用场景不同
I、策略模式是一系列平行的、可相互替换的算法封装后的结果,这就限定了它的应用场景:算法必须是平行的。
II、状态模式则要求有一系列状态发生变化的场景,它要求的是有状态且有行为的场景,也就是一个对象必须具有二维(状态和行为)描述才看采用状态模式
5)复杂度不同
I、策略模式比较简单,这里的简单指的是结构结点,扩展比较容易,而且代码也容易阅读。
II、状态模式则通常比较复杂,因为它要从两个角色看到一个对象状态和行为的改变,也就是说它封装的是变化,要知道变化是无穷尽的,因此相对比较复杂,涉及面多,虽然也容易扩展但一般不会进行大规模扩张与修改。
4、策略模式与桥梁模式的区别:
策略模式是一个行为模式,旨在封装一系列的行为;
而桥梁模式则是在不破坏封装的情况下抽取出它的抽象部分和实现部分,它的前提是不破坏封装,让抽象部分和实现部分都可以独立地变化。
简单来说,桥梁模式必然有两个“桥墩”---抽象化角色和实现化角色(抽象化角色(抽象的 如公司)调用实现化角色(具体的 如产品(公司生产的))),只要桥段搭建好,桥就有了,而策略模式只有一个抽象角色,可以没有实现,也可以很多实现。