策略模式定义
策略模式(Strategy Pattern)是一种行为型设计模式,定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式使得算法可以在不影响客户端的情况下发生变化,其主要目的是将算法的实现与使用解耦,提高程序的灵活性和可扩展性。
基本概念
- 策略(Strategy):定义了算法的通用接口,各种具体策略类实现该接口。
- 具体策略(Concrete Strategy):实现了策略接口,封装了具体的算法或行为。
- 上下文(Context):持有一个策略的引用,客户端通过上下文来与策略交互。
策略模式的种类
虽然策略模式本身没有明显的种类划分,但根据实现方式和应用场景的不同,可以有以下变体:
- 经典策略模式:使用接口或抽象类定义策略,具体策略类实现该接口,客户端通过上下文来使用策略。
- 匿名内部类或 Lambda 表达式:在支持函数式编程的语言中,可以使用匿名类或 Lambda 表达式简化策略的实现。
- 策略枚举:当策略数量固定时,可以使用枚举类型来实现不同的策略。
基本上使用1、3两种
使用场景
- 多种算法需要在运行时切换:如支付方式、排序算法等,根据不同的条件选择合适的算法。
-
避免大量的条件语句:使用策略模式可以替代
if-else
或switch
语句,提高代码的可读性和可维护性。 - 行为的变化需要独立于上下文:算法的变化不应影响使用它的代码,遵循开闭原则。
下面以最常用的场景,支付场景作为演示Demo
假设我们有一个电商平台,支持多种支付方式,如银联支付、支付宝和微信支付。
使用策略模式可以让支付方式的选择和实现独立,方便扩展新的支付方式。
1. 定义策略接口
// 支付策略接口
public interface PaymentStrategy {
void pay(double amount);
}
2. 实现具体策略
// 银联支付策略
public class UnionPayPayment implements PaymentStrategy {
private String cardNumber;
private String cardHolderName;
private String bankName;
public UnionPayPayment(String cardNumber, String cardHolderName, String bankName) {
this.cardNumber = cardNumber;
this.cardHolderName = cardHolderName;
this.bankName = bankName;
}
@Override
public void pay(double amount) {
// 银联支付的具体实现
System.out.println("使用银联卡支付 " + amount + " 元。");
}
}
// 支付宝支付策略
public class AlipayPayment implements PaymentStrategy {
private String alipayId;
public AlipayPayment(String alipayId) {
this.alipayId = alipayId;
}
@Override
public void pay(double amount) {
// 支付宝支付的具体实现
System.out.println("使用支付宝支付 " + amount + " 元。");
}
}
// 微信支付策略
public class WeChatPayment implements PaymentStrategy {
private String weChatId;
public WeChatPayment(String weChatId) {
this.weChatId = weChatId;
}
@Override
public void pay(double amount) {
// 微信支付的具体实现
System.out.println("使用微信支付 " + amount + " 元。");
}
}
3. 创建上下文类
// 购物车类,持有支付策略
public class ShoppingCart {
private List<Item> items;
private PaymentStrategy paymentStrategy;
public ShoppingCart() {
items = new ArrayList<>();
}
// 添加商品
public void addItem(Item item) {
items.add(item);
}
// 设置支付策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 结账
public void checkout() {
double total = calculateTotal();
paymentStrategy.pay(total);
}
// 计算总价
private double calculateTotal() {
double sum = 0;
for (Item item : items) {
sum += item.getPrice();
}
return sum;
}
}
4. 商品类
public class Item {
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
// 获取价格
public double getPrice() {
return price;
}
}
5. 客户端代码
public class Client {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
// 添加商品
cart.addItem(new Item("苹果", 10.0));
cart.addItem(new Item("香蕉", 20.0));
// 选择支付方式并支付
// 使用银联支付
PaymentStrategy unionPayPayment = new UnionPayPayment("6222020200000000", "张三", "中国银行");
cart.setPaymentStrategy(unionPayPayment);
cart.checkout();
// 使用支付宝支付
PaymentStrategy alipayPayment = new AlipayPayment("alipay_user_id");
cart.setPaymentStrategy(alipayPayment);
cart.checkout();
// 使用微信支付
PaymentStrategy weChatPayment = new WeChatPayment("wechat_user_id");
cart.setPaymentStrategy(weChatPayment);
cart.checkout();
}
}
输出结果:
使用银联卡支付 30.0 元。
使用支付宝支付 30.0 元。
使用微信支付 30.0 元。
6. 新增支付方式
如果需要新增一种支付方式,例如 Apple Pay,只需新增一个策略类:
// Apple Pay 支付策略
public class ApplePayPayment implements PaymentStrategy {
private String appleId;
public ApplePayPayment(String appleId) {
this.appleId = appleId;
}
@Override
public void pay(double amount) {
// Apple Pay 支付的具体实现
System.out.println("使用 Apple Pay 支付 " + amount + " 元。");
}
}
在客户端代码中使用:
// 使用 Apple Pay 支付
PaymentStrategy applePayPayment = new ApplePayPayment("apple_user_id");
cart.setPaymentStrategy(applePayPayment);
cart.checkout();
策略模式与抽象工厂模式的区别
虽然策略模式和抽象工厂模式都涉及到对象的创建和使用,但它们的目的和应用场景不同:
策略模式:关注算法的封装和互换,旨在运行时灵活地选择和切换算法。它将行为或算法抽象成独立的策略类,使得不同的策略可以互相替换,客户端通过上下文来使用策略。
抽象工厂模式:关注产品族的创建,旨在提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。抽象工厂模式主要用于创建对象,隐藏对象创建的细节,确保客户端使用的是同一产品族的对象。
区别总结:
目的不同:策略模式主要解决算法的选择和切换问题,抽象工厂模式主要解决对象的创建问题。
结构不同:策略模式包含策略接口和具体策略类,客户端通过上下文与策略交互;抽象工厂模式包含抽象工厂、具体工厂、抽象产品和具体产品,客户端通过工厂创建产品。
使用方式不同:策略模式强调算法的可替换性,通常在运行时决定使用哪种策略;抽象工厂模式强调产品族的一致性,通常在编译时就确定了具体的工厂和产品。
在支付场景中:
策略模式:我们使用策略模式来封装不同的支付方式(策略),如银联支付、支付宝支付、微信支付等。每种支付方式实现了相同的策略接口,可以互相替换,客户端可以在运行时选择不同的支付策略。
抽象工厂模式:假设我们需要创建一系列相关的支付对象,例如支付方式、支付验证、支付日志等,且这些对象在不同的平台(如国内支付平台、国际支付平台)有不同的实现。这时可以使用抽象工厂模式,提供一个接口来创建相关的支付对象,确保同一平台的对象一起工作。
策略模式的优势
- 符合开闭原则:添加新的策略无需修改原有代码,扩展性好。
- 避免使用多重条件判断:策略模式通过多态替代了条件判断,代码更简洁。
- 提高代码的灵活性:可以在运行时动态更换策略,满足不同的业务需求。
- 策略独立,便于维护:每个策略都封装在独立的类中,便于单独修改和测试。
- 可复用性高:策略类可以在不同的上下文中复用,减少重复代码。
策略模式的意义
- 解耦算法和使用场景:将算法的实现和使用它的代码分离,方便独立地更改或扩展算法。
- 提高系统的可维护性:算法的更改不影响上下文,降低了修改的风险。
- 满足不同的需求:通过灵活地选择策略,可以满足不同客户或环境的需求。
启发
策略模式的应用超越了代码层面,它体现了一种面向变化、拥抱变化的思想。在快速发展的技术领域,我们需要构建具有弹性和适应性的系统,以应对未来的挑战。通过合理地应用策略模式,我们可以设计出更具生命力的软件,为用户提供更好的体验。