文章目录
今天给大家介绍23种设计模式中的策略模式。🌈
一、什么是策略模式
策略模式(strategy pattern)的原始定义:定义一系列算法,将每一个算法封装起来,并使它们可以相互替换。策略模式让算法可以独立于使用它的客户端而变化。
其实在生活中我们常常会实现某种目标存在多种策略可供选择的情况,比如:出行旅游有很多种方式,乘坐飞机、高铁、火车等等,每种出行方式就好比一种策略。
二、为什么要使用策略模式
在软件开发中,经常会遇到这种情况,开发一项功能可以通过多个算法去实现,我们可以将所有的算法集中在一个类中,在这个类中提供多个方法,每个方法对应一个算法, 或者我们也可以将这些算法都封装在一个统一的方法中,使用if…else…等条件判断语句进行选择.但是这两种方式都存在硬编码的问题,后期需要增加算法就需要修改源代码,这会导致代码的维护变得很困难.使用策略模式能够很好的帮助我们解决这种问题。
三、如何使用策略模式
策略模式的主要角色如下:
- 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
- 环境或上下文(Context)类:是使用算法的角色, 持有一个策略类的引用,最终给客户端调用。
举一个支付的业务场景方便大家理解:
定义一个策略接口:
/**
* 说明: 定义一个支付的策略接口
*/
public interface PaymentStrategy {
String payType();
String pay(Long userId,Double amount);
}
实现具体的策略类:
//信用卡策略类
@Component
public class CreditCardPaymentStrategy implements PaymentStrategy{
@Override
public String payType() {
return PayEnum.SUBTRACTION.getName();
}
@Override
public String pay(Long userId, Double amount) {
return "使用信用卡支付成功,用户ID:" + userId + ",支付金额:" + amount;
}
}
//微信策略类
@Component
public class WechatPaymentStrategy implements PaymentStrategy{
@Override
public String payType() {
return PayEnum.ADDITION.getName();
}
@Override
public String pay(Long userId, Double amount) {
return "使用微信支付成功,用户ID:" + userId + ",支付金额:" + amount;
}
}
定义了支付类型的枚举:
public enum PayEnum {
SUBTRACTION(1,"信用卡支付"), ADDITION(2,"微信支付");
// 成员变量
private int index;
private String name;
private PayEnum( int index,String name) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (PayEnum c : PayEnum.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
public String getName() {
return name;
}
public int getIndex() {
return index;
}
}
通过一个Map来存储所有的策略实现,这里我实现了ApplicationContextAware接口,Spring容器初始化会自动将PaymentStrategy
的Bean添加到strategyMap当中去。
@Component
public class PaymentService implements ApplicationContextAware {
private final Map<String, PaymentStrategy> strategyMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String,PaymentStrategy> maps = applicationContext.getBeansOfType(PaymentStrategy.class);
maps.values().forEach(strategyService ->strategyMap.put(strategyService.payType(),strategyService));
}
public String pay(String strategyName, Long userId, double amount) {
PaymentStrategy strategy = strategyMap.get(strategyName);
if (strategy == null) {
throw new IllegalArgumentException("Unsupported payment strategy: " + strategyName);
}
return strategy.pay(userId, amount);
}
}
测试:
@Test
void testStrategy(){
System.out.println(paymentService.pay(PayEnum.WECHAT.getName(), 1L, 520.0));
//使用微信支付成功,用户ID:1,支付金额:520.0
}
总结
策略模式的优点:
- 开闭原则:策略模式对扩展开放,对修改封闭。你可以在不修改已有代码的情况下增加新的策略。
- 避免使用多重条件语句:使用策略模式,你可以避免在代码中使用多重条件语句(if-else 或 switch-case)。这使得代码更加清晰、易读,并且更易于维护。
- 客户端与算法解耦:策略模式使得算法可以独立于使用它的客户端变化。客户端只需要知道策略接口,而不需要知道具体的策略实现。
- 算法可以单独管理:策略模式允许你单独定义和管理策略类。这意味着你可以很容易地修改、增加或删除策略,而不会影响使用这些策略的客户端代码。
策略模式的缺点:
- 客户端必须知道策略的选择:虽然策略模式使得算法可以独立于客户端变化,但客户端仍然需要知道可用的策略并选择适当的策略。这可能会增加客户端的复杂性。
- 更多的对象:策略模式可能会增加系统中对象的数量,因为每个策略都是一个单独的类。这可能导致更大的内存占用。
- 性能考虑:由于每个策略都是一个单独的类,因此在运行时可能需要进行额外的对象创建和内存分配,这可能会影响性能。