本文字数:2502字,阅读大约需要 10 分钟。
在软件开发中,经常会遇到需要根据不同的条件来实现不同行为的场景。这种场景下,策略模式(Strategy Pattern)就是一种非常有用的设计模式。
策略模式属于行为型模式,允许我们定义一系列算法,并将其封装在独立的策略类中,使得它们可以互相替换。通过使用策略模式,我们能够灵活地选择和切换不同的算法,而无需修改原有的代码,替代⼤量 if else 的逻辑。
策略模式通常在以下情况下被使用:
例如:
这些只是策略模式的一些例子,实际应用场景非常丰富。通过使用策略模式,我们可以将算法或行为与具体的业务逻辑解耦,使得系统更加灵活和可扩展。
在策略模式中,有三个核心角色:上下文(Context)、策略接口(Strategy)和具体策略类(Concrete Strategy)。
下面我们来实现一下策略模式:
步骤 1
创建策略接口。
//策略接口
public interface PaymentStrategy {
void pay(double amount);
}
步骤2
创建策略接口实现类。
//具体策略类
public class CreditCardPayment implements PaymentStrategy {
public void pay(double amount) {
System.out.println("使用信用卡支付:" + amount);
// 具体的支付逻辑
}
}
public class WeChatPay implements PaymentStrategy {
public void pay(double amount) {
System.out.println("使用微信支付:" + amount);
// 具体的支付逻辑
}
}
注意:在实际项目中,我们一般通过工厂方法模式来实现策略类的声明。
实现关系如下:
步骤 3
创建 Context 类。
// 上下文类
public class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay(double amount) {
paymentStrategy.pay(amount);
}
}
调用一下:
// 使用示例
public class Main {
public static void main(String[] args) {
PaymentStrategy strategy = new CreditCardPayment();
PaymentContext context = new PaymentContext(strategy);
context.pay(100.0);
strategy = new WeChatPay();
context = new PaymentContext(strategy);
context.pay(200.0);
}
}
输出:
使用信用卡支付:100.0
使用微信支付:200.0
在上面的代码中,我们定义了一个 PaymentStrategy
接口作为策略接口,两个具体的策略类 CreditCardPayment
和 WeChatPay
实现了该接口。然后,我们创建了一个 PaymentContext
上下文对象,并根据需要传入不同的策略实例进行支付操作。
策略模式的优点包括:
策略模式的缺点包括:
注意事项: 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题,否则日后的系统维护就会成为一个烫手山芋。
我们可以将策略实现类放进 Map 中,根据 key 去选择具体的策略,就不必事先定义 Context 类。
public static void main(String[] args) {
Map<String, PaymentStrategy> map=new HashMap<>();
map.put("CREDIT_CARD", new CreditCardPayment());
map.put("WECHAT_PAY",new WeChatPay());
map.get("CREDIT_CARD").pay(100.0);
map.get("WECHAT_PAY").pay(200.0);
}
策略枚举可以解决策略类过多的问题。
我们对原装的策略模式进行改造,把原有定义在抽象策略中的方法移植到枚举中,让枚举成员成为一个具体策略。
@Slf4j
public enum PaymentStrategyEnum {
CREDIT_CARD {
@Override
public void pay(double amount) {
log.info("使用信用卡支付:" + amount);
// 具体的支付逻辑
}
},
WECHAT_PAY {
@Override
public void pay(double amount) {
log.info("使用微信支付:" + amount);
// 具体的支付逻辑
}
};
public abstract void pay(double amount);
}
在上面的代码中,我们定义了一个枚举类型 PaymentStrategy
,其中包含两个枚举常量 CREDIT_CARD
和 WECHAT_PAY
。每个枚举常量都重写了 pay()
方法,用于具体的支付逻辑。
// 使用示例
public static void main(String[] args) {
Map<String, PaymentStrategyEnum> map=new HashMap<>();
map.put("CREDIT_CARD", PaymentStrategyEnum.CREDIT_CARD);
map.put("WECHAT_PAY", PaymentStrategyEnum.WECHAT_PAY);
map.get("CREDIT_CARD").pay(100.0);
map.get("WECHAT_PAY").pay(200.0);
}
注意:策略枚举是一个非常优秀和方便的模式,但是它受枚举类型的限制,每个枚举项都是 public、final、static 的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一般担当不经常发生变化的角色。
SpringBoot中使用策略模式更加方便:
public interface Test {
void print(String name);
}
@Service("testA")
@Slf4j
public class TestA implements Test{
@Override
public void print(String name) {
log.info("实现类A"+name);
}
}
@Service("testB")
@Slf4j
public class TestB implements Test{
@Override
public void print(String name) {
log.info("实现类B"+name);
}
}
使用的时候 @Autowired
或者 @Resource
即可,SpringBoot会帮我们把实现类自动注入注入Map。
@Resource
private Map<String,Test> map;
Test test = map.get("你想拿出的具体策略类");
test.print("hello world");
策略模式是一种强大而灵活的设计模式,它可以帮助我们处理不同的算法或行为,并使系统更具可维护性和扩展性。通过封装具体的策略类和使用上下文对象,我们可以轻松地选择和切换不同的策略,而无需修改现有的代码。
希望这篇文章能给你带来收获和思考,如果你也有可借鉴的经验和深入的思考,欢迎评论区留言讨论。如果本文对你有帮助,请帮忙点个在看或者点个赞👍🏻。
点在看,让更多看见。
·················END·················