第3章 策略模式
- 格式:ppt
- 大小:697.00 KB
- 文档页数:34
策略模式详解
策略模式是一种行为型设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。
策略模式使得算法可以独立于使用它的客户端而变化。
策略模式适用于那些需要使用多种算法的问题。
由于每种算法都有其特殊的用途,因此客户端需要根据当前的情况选择最合适的算法。
在这种情况下,策略模式提供了一个灵活且可扩展的框架,使得算法的选择和使用变得简单且易于维护。
在策略模式中,有三个主要的参与者:
1. Strategy:策略接口定义了所有算法的公共接口,客户端通过这个接口来调用算法。
这样,客户端就不需要关心具体的算法实现,只需要根据需要选择相应的策略即可。
2. ConcreteStrategy:具体策略类实现了策略接口,并提供了具体的算法实现。
每个具体策略类都代表了一种特定的算法。
3. Context:上下文对象负责维护策略对象的实例,并根据需要切换不同的策略。
上下文对象通常会根据客户端的请求选择合适的策略对象,并将这个策略对象传递给客户端。
策略模式的优点在于它能够提供一种灵活且可扩展的解决方案,使得算法的选择和使用变得简单且易于维护。
由于策略对象是独立的,因此可以很容易地添加新的策略,而不需要修改现有的代码。
此外,策略模式还可以提供一种替换算法的方式,使得系统能够根据需要进
行动态的调整。
总之,策略模式是一种非常有用的行为型设计模式,它能够提供一种灵活且可扩展的解决方案来解决那些需要使用多种算法的问题。
策略模式及优化(本⽂参考了《设计模式之禅》⼀书)何时应该使⽤策略模式?当我们的程序中某些算法需要⾃由切换时⾮常适合使⽤策略模式。
⽐如我们写⼀个计算机程序,⾥⾯必然有加减乘除等等算法,并且这些算法还应该根据客户点击什么运算符号来⾃由切换。
我们就以加减算法的实现为例说明如何使⽤策略模式来优化代码,以及如何优化策略模式。
我们实现计算机的加减算法,最简单的写法应该是这样算法类public class Calculator {public final static String ADD = "+";public final static String SUB = "-";//算法加private static int add(int a,int b){return a + b;}//算法减private static int sub(int a,int b){return a - b;}//计算public static int exe(int a,int b,String exeMethod){switch (exeMethod) {case ADD:return add(a,b);case SUB:return sub(a,b);default:return0;}}}场景类public class Context {public static void main(String[] args) {int a = Calculator.exe(3, 4, Calculator.ADD); //加法运算int b = Calculator.exe(3, 4, Calculator.SUB); //减法运算System.out.println(a+""+b);}}现在我们引⼊策略模式先定义⼀个抽象接⼝public interface Strategy {int exe(int a,int b);}再实现加和减算法//加法public class CalculatorAdd implements Strategy{@Overridepublic int exe(int a, int b) {return a + b;}}//减法public class CalculatorSub implements Strategy{@Overridepublic int exe(int a, int b) {return a - b;}}可以看到,我们每个算法都继承了Strategy接⼝,并且实现的exe()⽅法。
策略模式(Strategy)●策略模式(Strategy Pattern)中体现了两个非常基本的面向对象设计的原则------------封装变化的概念------------变成中使用接口,而不是对接口的实现●面向接口的编程1.策略模式的定义1)定义一组算法,将每个算法都封装起来,并且使它们之间可以互换2)策略模式是这些算法在客户端调用它们的时候能够互不影响的变化2.策略模式的意义1)策略模式使开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间是弱连接的关系2)弱连接的特性使软件具有更强的可扩展性,易于维护;更重要的是:它大大提高了软件的可重用性3.策略模式的组成1)抽象策略角色:策略类,通常由一个接口或者抽象类实现,比如:Comparator 2)具体策略角色:包装了相关的算法和行为,比如接口的多个实现类3)环境角色:持有一个策略类的引用,最终给客户端调用的,比如:TreeSet,TreeMap4.策略模式的实现1)策略模式的用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换2)策略模式使得算法可以在不影响到客户端的情况下发生变化。
使用策略模式可以把行为和环境分割开来3)环境类负责维持和查询行为类,各种算法则在具体策略中提供。
由于算法和环境独立开来,算法的修改都不会影响环境和客户端5.策略模式的编写步骤1)对策略对象定义一个公共接口(抽象策略角色)2)编写具体策略类,该类实现了上面的公共接口3)在使用具体策略对象的类中保存一个对抽象策略对象的引用(环境角色)4)在使用策略对象的类中,实现对策略对象的set和get方法(注入)或者使用构造方法完成赋值(客户端)6.参看JDK Collections类的源代码7.策略模式的缺点1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类2)造成很多的策略类8.解决方法采用工厂方法(一种设计模式)。
策略模式以及策略模式与模板⽅法的结合
在上⼀篇中我提到了⽤模板⽅法模式来重构以前写过的代码,在看到的留⾔后,我重新审视了⼀下⾃⼰的代码,到底⽤策略模式呢,还是模板⽅法呢?她们之间有没有共性可以抽取出来?
从策略模式的定义中可以看出,策略模式是对⼀组相似算法的包装,使得算法的实现与算法使⽤环境相隔离,在⽗类中提供算法的统⼀接⼝以供环境对象Context调⽤,以最瘦⼩的策略模式实现来说实际上是不满⾜我的需求的,因为我的算法中还包含更多的⼦操作、⼦流程,⽽这些流程⼜很相象,她们的调⽤逻辑框架也是相象的,怎么办?把这些逻辑直接写在Common接⼝中?重构逻辑?将⼦逻辑独⽴出来给出统⼀定义并由⼦类实现?呵呵!越说越象Template Pattern了。
那么我们就把中的代码重新构造⼀下:
实际上从代码中可以看出,从整体结构上讲应该算是策略模式的应⽤,实现了策略实现与环境的分离,由环境决定采⽤什么策略(当然这也是策略模式的⼀个缺点,环境必须知道所有的策略,并知道应该⽤什么策略),但从策略的统⼀接⼝来说⼜可以说是⼀个模板⽅法,不知道把这个运⽤说成是策略模式和模板⽅法的结合是否牵强?
其实归根结底,在这两种模式的运⽤中最原始的东西是什么?正如在他的中所讲的⼀样,是多态的运⽤。
策略模式的实际应用策略模式是一种常用的设计模式,它可以帮助我们实现在不同情况下选择不同的策略来完成相同的任务。
在实际应用中,策略模式有着广泛的应用场景,例如在电商平台的促销活动中、交通运输系统中的路径规划、游戏中的角色选择等等。
在电商平台的促销活动中,策略模式可以帮助商家根据不同的促销策略来吸引消费者。
例如,商家可以根据消费者的购买历史、购买频率以及消费金额等信息,制定不同的促销策略。
对于新用户,可以提供首次购物的优惠券;对于老用户,可以根据其购买金额给予不同程度的折扣。
通过使用策略模式,商家可以根据不同的情况来选择合适的促销策略,以提高销售额和用户满意度。
在交通运输系统中的路径规划中,策略模式可以帮助用户选择最佳的出行方式。
例如,在一个城市中,用户想要从A地到达B地,可以有多种出行方式,如步行、公交、地铁、出租车等。
不同的出行方式有着不同的时间花费、费用和舒适度等因素。
通过使用策略模式,系统可以根据用户的出行需求和偏好,选择最佳的出行方式并提供最佳的路径规划。
在游戏中的角色选择中,策略模式可以帮助玩家根据不同的游戏情况选择最适合的角色。
例如,在一款多人在线游戏中,不同的角色具有不同的技能、属性和特点,玩家可以根据自己的游戏风格和战术选择合适的角色。
某些角色可能适合近战战斗,某些角色可能适合远程攻击,而某些角色则可能适合辅助和治疗。
通过使用策略模式,玩家可以根据游戏情况和自己的游戏风格选择最佳的角色,以提高游戏体验和胜率。
除了以上应用场景,策略模式还可以应用于许多其他领域,如金融投资中的资产配置、机器人控制中的路径规划、智能家居中的节能调控等等。
通过使用策略模式,我们可以根据不同的情况和需求选择最佳的策略,从而提高系统的灵活性、可扩展性和可维护性。
总结起来,策略模式是一种非常实用的设计模式,它可以帮助我们在不同情况下选择最佳的策略来完成相同的任务。
在电商平台的促销活动、交通运输系统的路径规划、游戏中的角色选择等实际应用场景中,策略模式都发挥了重要的作用。
策略模式之两型--动态策略模式和静态策略模式策略模式⼀般是反应⾯向对象语⾔的多态特性,即可在运⾏时更改或选择不同的策略,典型的使⽤⽅式如下:class Strategy{public:Strategy() {}virtual ~Strategy() {}virtual int stopTask() = 0;};//策略Aclass Strategy_A : public Strategy{public:Strategy_A(): Strategy() {}~Strategy_A() {}//virtualint stopTask(){//do your strategy-A}};//策略Bclass Strategy_B : public Strategy{public:Strategy_B(): Strategy() {}~Strategy_B() {}//virtualint stopTask(){//do your strategy-B}};//使⽤时,你可以根据情况或条件(变量),让⽗对象指针指向⼀个实际构造的⼦对象Strategy* pOptionChose = new Strategy_B(); //遇到其他情况,你也可以指向⼀个new Strategy_A()-------------------------------------------------以上就是⼀般的策略模式的⽤法,可以称之为动态策略模式;实际上C++也可以⽤模板来实现,或称之为静态策略模式,这样实现的策略模式有编译期特性,即⼀经编译即固化了策略,特别适⽤于⾯向不同的客户做定制化⽅案的情形。
其⽤法如下:class StrategyA{public:void fun_1(){//do your strategy-A's fun_1}//....void fun_n(){//do your strategy-A's fun_n}};class StrategyB{public:void fun_1(){//do your strategy-B's fun_1}//...void fun_n(){//do your strategy-B's fun_n}};template<class T>class Context{public:void fun_1(){strategy.fun_1();}//...void fun_n(){strategy.fun_n();}private:T strategy;};如上所⽰,类StrategyA和StrategyB除了有同样的fun_1()到fun_n()这n个同名的⽅法外,并没有其他关系;模板类Context<T>中也有上述n个同名⽅法,实际使⽤时,只有根据情况具象化⼀个⾃⼰想要的⼀个策略实例即可,⽐如Context<StrategyA> intance;然后让实例intance调⽤任何想要的⽅法就可以了,⽐如intance.fun_1();就是执⾏类StrategyA中的fun_1()⽅法。
策略模式与简单⼯⼚模式的结合使⽤ Java设计模式中的策略模式(Strategy Patten)定义了⼀组算法,将每个算法都封装起来,并且可使它们之间可以相互替换,在客户端调⽤它们时可以互不影响。
策略模式主要由三个⾓⾊组成1、抽象策略⾓⾊:通常是⼀个接⼝或抽象类实现,我们的具体策略类就是继承或实现这个抽象⾓⾊。
2、具体策略⾓⾊:我们在这些类中写策略和算法,继承或实现抽象策略⾓⾊。
3、环境⾓⾊:环境⾓⾊中拥有⼀个抽象策略⾓⾊的引⽤,供客户端调⽤,该⾓⾊把客户端跟策略类的实现分离。
从上⾯的三个策略模式的⾓⾊中,我们就⼤概可以知道策略模式的编写步骤,这⾥以实现简单的四则运算为例。
1、定义抽象策略⾓⾊,也就是定义⼀个公共的抽象类(也可以是接⼝)1package strategy;2/**3 *4 * @author CIACs5 *定义抽象策略⾓⾊6*/7public abstract class Strategy {8//定义抽象策略的⽅法9public abstract int strategy(int a,int b);1011 }2、编写策略类,该类实现上⾯定义的抽象类1package strategy;2/**3 *4 * @author CIACs5 * AddStrategy6*/7public class AddStrategy extends Strategy {8//定义实现加法的策略⽅法9public int strategy(int a, int b)10 {11return a+b;12 }1314 }1package strategy;2/**3 *4 * @author CIACs5 * SubStrategy6*/7public class SubStrategy extends Strategy {8//定义减法的策略⽅法9public int strategy(int a, int b)10 {11return a-b;12 }1314 }1package strategy;2/**3 *4 * @author CIACs5 * MultiplyStrategy6*/7public class MultiplyStrategy extends Strategy {8//定义乘法的策略⽅法9public int strategy(int a,int b)10 {11return a*b;12 }13 }1package strategy;2/**3 *4 * @author CIACs5 * DivStrategy6*/7public class DivStrategy extends Strategy {8//定义除法的策略⽅法,这⾥为了简单就不考虑除数为零的情况了 9public int strategy(int a,int b)10 {11return a/b;12 }13 }3、编写环境⾓⾊,其中持有⼀个抽象策略类的引⽤1package strategy;2/**3 *4 * @author CIACs5 * Context6*/7public class Context {8//持有抽象策略⾓⾊的引⽤,⽤于客户端调⽤9private Strategy strategy;10//获得策略类11public Strategy getStrategy() {12return strategy;13 }14//设置所需策略15public void setStrategy(Strategy strategy) {16this.strategy = strategy;1718 }19//根据设置的策略类返回对应的结果20public int getResult(int a,int b)21 {22return strategy.strategy(a, b);23 }2425 }4、编写客户端1package strategy;2/**3 *4 * @author CIACs5 * Client6*/7public class Client {8public static void main(String[] args) {910 Context context = new Context();1112int result;1314 context.setStrategy(new SubStrategy());1516 result = context.getResult(9, 3);1718 System.out.println("sub: "+result);1920 context.setStrategy(new AddStrategy());2122 result =context.getResult(9, 3);2324 System.out.println("add: "+result);2526 context.setStrategy(new DivStrategy());2728 result = context.getResult(9, 3);2930 System.out.println("div: "+result);3132 context.setStrategy(new MultiplyStrategy());3334 result = context.getResult(9, 3);3536 System.out.println("mul: "+result);37 }38 }输出结果:上⾯只是⽤到策略模式,下⾯加上简单⼯⼚模式⼯⼚类1package strategy;2/**3 *4 * @author CIACs5 * Factory6*/7public class Factory {8public Strategy createStrategy(String str)9 {10if("AddStrategy".equalsIgnoreCase(str))11 {12return new AddStrategy();13 }14else15if("SubStrategy".equalsIgnoreCase(str))16 {17return new SubStrategy();18 }19else20if("DivStrategy".equalsIgnoreCase(str))21 {22return new DivStrategy();23 }24else25if("MultiplyStrategy".equalsIgnoreCase(str))26 {27return new MultiplyStrategy();28 }29else30return null;31 }3233 }客户端类1package strategy;2/**3 *4 * @author CIACs5 * Client6*/7public class Client {8public static void main(String[] args) {910 Context context = new Context();11int result;12 Strategy strategy;13 Factory fac = new Factory();14 strategy = fac.createStrategy("AddStrategy");15 context.setStrategy(strategy);16 result = context.getResult(9, 3);17 System.out.println(result);18 }19 }输出结果:当然这⾥的⼯⼚类中的if-else的使⽤是不太好的,简单⼯⼚模式把⽣成策略类与客户端分离。
模板方法模式和策略模式模板方法模式模板方法模式是一种对对象行为的抽象化,它是将某个对象的行为提取出来,封装在方法中,那么该模式就是将某类的行为的设计抽象化,通过抽象化可以简化该类调用时的复杂度。
模板方法模式定义了一个算法的步骤,并将这些步骤的实现延迟到子类中。
这样,即使子类实现了不同的行为,它们仍然可以按照抽象类中定义的步骤去执行。
模板方法模式有以下几个角色:(1)抽象类:抽象类可以定义算法的步骤,它将每一步定义为一个抽象方法,需要子类去实现,但是它不需要指定算法的具体实现步骤;(2)具体子类:由于算法的具体实现步骤由子类来完成,所以它可以完成算法中与特定操作相关而将封装在抽象类中的步骤,也可以重写父类定义的抽象方法;(3)客户端:通常是主函数,负责创建具体子类的实例,并调用其中的某些方法来实现算法的步骤。
模板方法模式的使用场景(1)在某些业务中,多个子类之间存在大量的公用代码,可以将这些公用的代码放到一个父类的模板方法中,以此来减少代码的重复性;(2)当处理某类型问题时,不同的子类可能会提供不同的解决方案,而抽象类可以把这些解决方案整合到一个模板方法中,从而利用这种抽象性去解决具体的问题。
策略模式策略模式是一种行为设计模式,它定义了可以互换的算法族,并且使它们之间可以相互替换。
该模式使得算法可独立于使用它的客户而变化。
策略模式可以看作是一种用于替换多重条件分支语句的更好方案。
(1)环境类:环境类是一个使用策略类的客户端,它可以对一个策略对象进行配置、用于在运行时选择算法;(2)抽象策略:抽象策略类是一类算法的抽象,功能和接口都可以在该抽象类中定义;(4)客户端:使用环境类的客户端,可以使用不同的算法来实现不同的业务,它可以根据实际情况替换策略。
(1)当一个系统具有多种处理某一个问题的算法,并且客户端需要动态地在这些算法中选择一种解决方案时,可以采用策略模式;(2)当系统需要根据外部条件来选择不同的算法时,可以使用策略模式;(3)当一个对象有很多的行为相似,可以采用策略模式,把相似的行为放到一个策略类中,使结构更加清晰。
策略模式与模板⽅法模式1. 策略模式策略模式是⼀种⾏为设计模式,它能让你定义⼀系列算法,并将每种算法分别放⼊独⽴的类中,以使算法的对象能够相互替换。
当你有许多仅在执⾏某些⾏为时略有不同的相似类时,可使⽤策略模式。
使⽤该模式能将类的业务逻辑与其算法实现细节隔离开来。
说⽩了,其实还是解耦策略模式的结构如上图所⽰,主要包含三个⾓⾊:抽象⾓⾊:通常是⼀个接⼝具体⾓⾊:接⼝的具体实现环境⾓⾊:调⽤接⼝的上下⽂环境,通常是⼀段业务逻辑⽅法举个常见的例⼦:⽀付先定义⼀个接⼝ PayStrategy.javapackage com.example.service;import com.example.domain.dto.PayDTO;import com.example.domain.dto.PayDetailDTO;/*** @author ChengJianSheng* @date 2021/1/11*/public interface PayStrategy{/*** 下单*/PayDTO prepay();/*** 查询*/PayDetailDTO query();/*** 撤销*/void cancel();/*** 退款*/void refund();}然后是具体实现AlipayStrategy.javapackage com.example.service.impl;import com.alipay.api.AlipayClient;import com.alipay.api.request.AlipayTradePrecreateRequest;import com.alipay.api.response.AlipayTradeCancelResponse;import com.example.domain.dto.PayDTO;import com.example.domain.dto.PayDetailDTO;import com.example.service.PayStrategy;import org.springframework.beans.factory.annotation.Autowired;import ponent;/*** https:///open/common/abilitymap* https:///open/194/106078* 扫码⽀付*/@Componentpublic class AlipayStrategy implements PayStrategy{@Autowiredprivate AlipayClient alipayClient;@Overridepublic PayDTO prepay(){AlipayTradePrecreateRequest request=new AlipayTradePrecreateRequest();AlipayTradeCancelResponse response=alipayClient.execute(request);return null;}@Overridepublic PayDetailDTO query(){return null;}@Overridepublic void cancel(){}@Overridepublic void refund(){}public void payNotify(String data){}public void refundNotify(){}}WeixinPayStrategy.javapackage com.example.service.impl;import com.example.domain.dto.PayDTO;import com.example.domain.dto.PayDetailDTO;import com.example.service.PayStrategy;import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.service.WxPayService;import org.springframework.beans.factory.annotation.Autowired;import ponent;/*** https:///wiki/doc/apiv3/wxpay/pages/index.shtml* https:///Wechat-Group/WxJava/wiki/%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98 * @author ChengJianSheng* @date 2021/1/11*/@Componentpublic class WeixinPayStrategy implements PayStrategy{@Autowiredprivate WxPayService wxPayService;@Overridepublic PayDTO prepay(){WxPayUnifiedOrderRequest request=new WxPayUnifiedOrderRequest();wxPayService.createOrder(request);return null;}@Overridepublic PayDetailDTO query(){WxPayOrderQueryRequest request=new WxPayOrderQueryRequest();wxPayService.queryOrder(request);return null;}@Overridepublic void cancel(){}@Overridepublic void refund(){}public void payNotify(String data){WxPayOrderNotifyResult result=wxPayService.parseOrderNotifyResult(data);}public void refundNotify(String data){WxPayOrderNotifyResult result=wxPayService.parseRefundNotifyResult(data);}}上下⽂package com.example.service.impl;import com.example.domain.dto.PayDTO;import com.example.service.PayService;import com.example.service.PayStrategy;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;/*** @author ChengJianSheng* @date 2021/1/11*/@Servicepublic class PayServiceImpl implements PayService{@Autowiredprivate AlipayStrategy alipayStrategy;@Autowiredprivate WeixinPayStrategy weixinPayStrategy;@Overridepublic void prePay(PayDTO payDTO){// 创建⽀付订单// 组装参数PayStrategy payStrategy=null;if(payDTO.getChannel()==1){payStrategy=alipayStrategy;}else{payStrategy=weixinPayStrategy;}payStrategy.prepay();}}这样就将算法的细节与业务逻辑隔离开,开发始终要遵循的原则是:⾼内聚,低耦合其余部分代码补充如下:pom.xml<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.11.8.ALL</version></dependency><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>4.0.0</version></dependency>AlipayConfig.javapackage com.example.config;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** 扫码⽀付* https:///open/194/106078* https:///open/common/abilitymap** @author ChengJianSheng* @date 2021/1/11*/@Configurationpublic class AlipayConfig{@Value("${alipay.appId}")private String appId;@Value("${alipay.privateKey}")private String privateKey;@Value("${alipay.publicKey}")private String publicKey;@Beanpublic AlipayClient alipayClient(){AlipayClient alipayClient=new DefaultAlipayClient("https:///gateway.do",appId,privateKey,"json","UTF-8",publicKey,"RSA2");return alipayClient;}}WeixinPayConfig.javapackage com.example.config;import com.github.binarywang.wxpay.config.WxPayConfig;import com.github.binarywang.wxpay.service.WxPayService;import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/*** https:///wiki/doc/apiv3/index.shtml* https:///Wechat-Group/WxJava/wiki/%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98* @author ChengJianSheng* @date 2021/1/11*/@Configurationpublic class WeixinPayConfig{/*** 公众号appid*/@Value("${weixin.pay.appId}")private String appId;/*** 商户号.*/@Value("${weixin.pay.mchId}")private String mchId;/*** 商户密钥.*/@Value("${weixin.pay.mchKey}")private String mchKey;@Value("${weixin.pay.notifyUrl}")private String notifyUrl;@Beanpublic WxPayService wxPayService(){WxPayConfig payConfig=new WxPayConfig();payConfig.setAppId(appId);payConfig.setMchId(mchId);payConfig.setMchKey(mchKey);payConfig.setNotifyUrl(notifyUrl);WxPayService wxPayService=new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}}2. 模板⽅法模式模板⽅法模式是⼀种⾏为设计模式,它在超类中定义了⼀个算法的框架,允许⼦类在不修改结构的情况下重写算法的特定步骤。