在现实生活中常常遇到达成某种目的,有多种实现策略可供选择的情况。例如,出行上班可以乘坐公交车、乘坐地铁、骑自行车或自己开私家车等,填饱肚子可以吃火锅、吃烤肉、吃烤串、吃东北家常菜等方法。
在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、堆排序、二叉树排序等。
上述情况在软件开发中就对应策略模式,接下来,请进入策略模式的世界。
策略模式的定义
策略模式(Strategy Pattern)属于行为型设计模式,其定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。在策略模式中,创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
策略模式的实现
策略模式角色
- 环境角色(Context):维护一个对策略对象的引用,提供给客户端使用,负责将客户端请求委派给具体的策略对象执行。不需要知道具体策略类的实现细节,只需知道策略类实现了共同接口。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
- 抽象策略角色(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略角色(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的相关的算法和行为实现。
策略模式类图
策略模式举例
在网购中,当需要进行在支付的时候,可以根据实际情况来选择不同的支付方式(微信支付、支付宝、银行卡支付等等),这些支付方式即是不同的策略。不同的支付方式就是不同的支付策略。
策略模式代码实现
抽象策略角色
package com.common.demo.pattern.strategy;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 抽象策略角色 第三方支付
* @date 2023/08/08 21:31:29
*/
public interface PaymentStrategy {
/**
* 获取支付方式
*
* @return 响应,支付方式
*/
String getPayType();
}
具体策略角色
package com.common.demo.pattern.strategy;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体策略角色 支付宝支付
* @date 2023/08/08 21:30:54
*/
public class AlipayPaymentStrategy implements PaymentStrategy {
@Override
public String getPayType() {
System.out.println("支付宝支付");
return "支付宝支付";
}
}
package com.common.demo.pattern.strategy;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体策略角色 银行卡支付
* @date 2023/08/08 21:30:54
*/
public class BankCardPaymentStrategy implements PaymentStrategy {
@Override
public String getPayType() {
System.out.println("银行卡支付");
return "银行卡支付";
}
}
package com.common.demo.pattern.strategy;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 具体策略角色 微信支付
* @date 2023/08/08 21:30:54
*/
public class WxPaymentStrategy implements PaymentStrategy {
@Override
public String getPayType() {
System.out.println("微信支付");
return "微信支付";
}
}
环境角色
package com.common.demo.pattern.strategy; /** * @author Evan Walker 昂焱数据: https://www.ayshuju.com * @version 1.0 * @desc 环境角色 环境 * @date 2023/08/08 21:38:29 */ public class Context { private PaymentStrategy paymentStrategy; public Context(PaymentStrategy paymentStrategy){ this.paymentStrategy = paymentStrategy; } public String getPayType(){ return paymentStrategy.getPayType(); } }
测试代码
package com.common.demo.pattern.strategy;
/**
* @author Evan Walker 昂焱数据: https://www.ayshuju.com
* @version 1.0
* @desc 测试类
* @date 2023/08/08 21:40:38
*/
public class Test {
public static void main(String[] args) {
Context alipay = new Context(new AlipayPaymentStrategy());
System.out.println(alipay.getPayType());
Context Wx = new Context(new WxPaymentStrategy());
System.out.println(Wx.getPayType());
Context bankcard = new Context(new BankCardPaymentStrategy());
System.out.println(bankcard.getPayType());
}
}
测试角色
策略模式的特点
优点
- 提高代码灵活性:策略模式可以将算法的选择和使用与客户端代码分离,使得算法可以独立演化和替换,提高了代码的灵活性。
- 易于扩展和维护:由于每个策略都是一个独立的类,所以新的策略可以相对容易地添加到系统中,同时也可以方便地修改或维护现有的策略类。
- 符合开闭原则:新增策略时无需修改原有代码,只需添加新的策略类即可。
- 职责分离:策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点
- 增加了类的数量:使用策略模式会增加多个策略类,导致类的数量增加。
- 客户端需要了解不同的策略:客户端需要了解所有可用的策略以及它们之间的区别,可能会增加客户端的复杂性。
使用场景
- 当有多个算法可以互相替换,并且客户端不应该知道具体的算法实现时,可以考虑使用策略模式。
- 当需要根据不同的情况选择不同的算法时,可以使用策略模式。
- 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
注意事项
- 策略间的平等性:在策略模式中,各个策略应该是平等的,没有优劣之分,它们只是针对同一问题的不同解决方案。
- 接口的定义和使用:在策略模式中,通常通过接口或抽象类定义策略,以便于扩展和替换。
实际应用
- 支付方式选择:一个电商系统可以根据用户的选择,采用不同的支付策略(如支付宝、微信支付、银行卡支付)。
- 排序算法:排序算法可以采用不同的策略实现(如冒泡排序、快速排序、归并排序)。
- 策略游戏中的战略选择:在策略游戏中,可以根据不同的战略选择不同的作战策略。
更多消息资讯,请访问昂焱数据(https://www.ayshuju.com)