1.策略模式的基础使用
策略模式是一种行为型设计模式,核心思想是将算法(或行为)封装为独立的策略类,使它们可以互相替换,从而让算法的变化独立于使用算法的客户端 。这种模式能有效解决代码中大量if-else或switch判断的问题,符合 "开闭原则"(对扩展开放,对修改关闭)。
策略模式的核心角色
- 抽象策略(Strategy):定义所有具体策略的公共接口(或抽象类),声明策略执行的方法。
- 具体策略(Concrete Strategy):实现抽象策略接口,封装具体的算法逻辑。
- 环境(Context):持有策略对象的引用,负责调用策略的方法(不直接实现算法,而是委托给策略对象)。
代码案例:支付方式选择场景
假设一个电商系统需要支持多种支付方式(信用卡、支付宝、微信支付),且未来可能新增其他支付方式。使用策略模式可以灵活切换支付方式,无需修改核心逻辑。
1. 定义抽象策略(支付策略接口)
抽象策略接口定义所有支付方式的统一规范(此处方法pay)。
// 抽象策略:支付策略接口
public interface PaymentStrategy {
// 支付方法(参数为支付金额)
void pay(double amount);
}
2. 实现具体策略(具体支付方式)
每种支付方式作为具体策略,实现PaymentStrategy接口,封装各自的支付逻辑。
// 具体策略1:信用卡支付
public class CreditCardPayment implements PaymentStrategy {
// 信用卡相关信息(实际场景中需加密处理)
private String cardNumber;
private String cardHolderName;
public CreditCardPayment(String cardNumber, String cardHolderName) {
this.cardNumber = cardNumber;
this.cardHolderName = cardHolderName;
}
@Override
public void pay(double amount) {
System.out.printf("使用信用卡支付:卡号%s(持卡人:%s),金额:%.2f元%n",
maskCardNumber(cardNumber), cardHolderName, amount);
}
// 辅助方法:隐藏卡号中间位数(安全处理)
private String maskCardNumber(String cardNumber) {
if (cardNumber.length() < 16) return cardNumber;
return cardNumber.substring(0, 4) + " **** **** " + cardNumber.substring(12);
}
}
// 具体策略2:支付宝支付
public class AlipayPayment implements PaymentStrategy {
private String alipayAccount; // 支付宝账号(手机号或邮箱)
public AlipayPayment(String alipayAccount) {
this.alipayAccount = alipayAccount;
}
@Override
public void pay(double amount) {
System.out.printf("使用支付宝支付:账号%s,金额:%.2f元%n", alipayAccount, amount);
}
}
// 具体策略3:微信支付
public class WechatPayment implements PaymentStrategy {
private String wechatId; // 微信账号(微信号或手机号)
public WechatPayment(String wechatId) {
this.wechatId = wechatId;
}
@Override
public void pay(double amount) {
System.out.printf("使用微信支付:账号%s,金额:%.2f元%n", wechatId, amount);
}
}
3. 定义环境类(购物车)
环境类持有策略对象的引用,负责调用策略的方法(不关心具体支付逻辑,只委托给策略)。
// 环境类:购物车(负责使用支付策略)
public class ShoppingCart {
// 持有支付策略的引用
private PaymentStrategy paymentStrategy;
// 设置支付策略(允许动态切换)
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 结算(委托给策略对象执行支付)
public void checkout(double totalAmount) {
if (paymentStrategy == null) {
throw new IllegalStateException("请先设置支付方式");
}
paymentStrategy.pay(totalAmount);
}
}
4. 客户端使用(测试代码)
客户端根据需求选择具体策略,通过环境类调用策略方法,无需关心策略的实现细节。
public class Client {
public static void main(String[] args) {
// 创建购物车(环境对象)
ShoppingCart cart = new ShoppingCart();
// 场景1:使用信用卡支付
PaymentStrategy creditCard = new CreditCardPayment("6222021234567890123", "张三");
cart.setPaymentStrategy(creditCard);
cart.checkout(399.99); // 输出:使用信用卡支付:卡号6222 **** **** 0123(持卡人:张三),金额:399.99元
// 场景2:切换为支付宝支付
PaymentStrategy alipay = new AlipayPayment("zhangsan@163.com");
cart.setPaymentStrategy(alipay);
cart.checkout(159.50); // 输出:使用支付宝支付:账号zhangsan@163.com,金额:159.50元
// 场景3:切换为微信支付
PaymentStrategy wechat = new WechatPayment("wx_zhangsan123");
cart.setPaymentStrategy(wechat);
cart.checkout(99.00); // 输出:使用微信支付:账号wx_zhangsan123,金额:99.00元
}
}
策略模式的优点
- 灵活性高:客户端可动态切换策略(如示例中切换支付方式),无需修改环境类代码。
- 避免冗余判断 :用策略类替换
if-else或switch,减少代码复杂度。 - 易于扩展:新增策略只需实现抽象接口(如新增 "银联支付"),符合开闭原则。
2.策略模式的嵌套使用
下面以电商订单价格计算场景为例,展示策略模式的嵌套使用。在该场景中,订单价格计算策略会嵌套折扣策略,而折扣策略内部又可能包含组合折扣策略,形成多层策略嵌套。
场景说明
电商订单的最终价格计算涉及:
- 基础价格计算策略(常规价 / 会员价)
- 折扣策略(嵌套在基础计算中):
- 百分比折扣
- 固定金额折扣
- 组合折扣(嵌套多个子折扣策略)
代码实现
1. 折扣策略接口(内层策略)
定义折扣计算的抽象行为,所有具体折扣策略需实现此接口。
/**
* 折扣策略接口(内层策略)
*/
public interface DiscountStrategy {
// 计算折扣后价格(参数:原价)
double calculateDiscount(double originalPrice);
}
2. 具体折扣策略(内层策略实现)
包括基础折扣和组合折扣(组合折扣会嵌套其他折扣策略)。
/**
* 百分比折扣(如9折)
*/
public class PercentageDiscount implements DiscountStrategy {
private double percentage; // 折扣比例(0.9代表9折)
public PercentageDiscount(double percentage) {
this.percentage = percentage;
}
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * percentage;
}
}
/**
* 固定金额折扣(如减50元)
*/
public class FixedDiscount implements DiscountStrategy {
private double fixedAmount; // 固定减免金额
public FixedDiscount(double fixedAmount) {
this.fixedAmount = fixedAmount;
}
@Override
public double calculateDiscount(double originalPrice) {
// 确保折扣后价格不低于0
return Math.max(originalPrice - fixedAmount, 0);
}
}
/**
* 组合折扣(嵌套多个子折扣策略,按顺序叠加)
*/
public class CombinedDiscount implements DiscountStrategy {
private List<DiscountStrategy> discountStrategies; // 嵌套的子折扣策略
public CombinedDiscount(List<DiscountStrategy> discountStrategies) {
this.discountStrategies = discountStrategies;
}
@Override
public double calculateDiscount(double originalPrice) {
double price = originalPrice;
// 依次应用所有子折扣策略(策略嵌套)
for (DiscountStrategy strategy : discountStrategies) {
price = strategy.calculateDiscount(price);
}
return price;
}
}
3. 价格计算策略接口(外层策略)
定义订单价格计算的抽象行为,依赖折扣策略(内层策略)。
/**
* 价格计算策略接口(外层策略)
*/
public interface PriceCalculationStrategy {
// 计算订单最终价格(参数:商品原价总和、折扣策略)
double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy);
}
4. 具体价格计算策略(外层策略实现)
包括常规价计算和会员价计算,均会嵌套使用折扣策略。
/**
* 常规价格计算策略(无基础优惠,直接应用折扣)
*/
public class RegularPriceStrategy implements PriceCalculationStrategy {
@Override
public double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy) {
// 嵌套使用折扣策略
return discountStrategy.calculateDiscount(totalOriginalPrice);
}
}
/**
* 会员价格计算策略(基础价先打9.5折,再应用其他折扣)
*/
public class MemberPriceStrategy implements PriceCalculationStrategy {
@Override
public double calculateFinalPrice(double totalOriginalPrice, DiscountStrategy discountStrategy) {
// 1. 先应用会员基础折扣(9.5折)
double memberPrice = totalOriginalPrice * 0.95;
// 2. 再嵌套使用外部传入的折扣策略(如促销折扣)
return discountStrategy.calculateDiscount(memberPrice);
}
}
5. 订单上下文类(使用策略)
封装策略的调用,对外提供统一的价格计算入口。
/**
* 订单类(策略上下文)
*/
public class Order {
private double totalOriginalPrice; // 商品原价总和
private PriceCalculationStrategy calculationStrategy; // 外层价格计算策略
private DiscountStrategy discountStrategy; // 内层折扣策略
public Order(double totalOriginalPrice,
PriceCalculationStrategy calculationStrategy,
DiscountStrategy discountStrategy) {
this.totalOriginalPrice = totalOriginalPrice;
this.calculationStrategy = calculationStrategy;
this.discountStrategy = discountStrategy;
}
// 计算最终价格(委托给策略)
public double getFinalPrice() {
return calculationStrategy.calculateFinalPrice(totalOriginalPrice, discountStrategy);
}
}
6. 测试代码
演示不同策略组合(包括多层嵌套)的效果。
public class StrategyNestingDemo {
public static void main(String[] args) {
double originalPrice = 1000; // 商品原价总和1000元
// 场景1:常规价格 + 9折优惠
Order order1 = new Order(
originalPrice,
new RegularPriceStrategy(),
new PercentageDiscount(0.9)
);
System.out.println("常规价+9折:" + order1.getFinalPrice()); // 900.0
// 场景2:会员价格 + 减200元优惠
Order order2 = new Order(
originalPrice,
new MemberPriceStrategy(),
new FixedDiscount(200)
);
System.out.println("会员价+减200:" + order2.getFinalPrice()); // 750.0(1000*0.95=950,950-200=750)
// 场景3:会员价格 + 组合折扣(先9折再减100元)
List<DiscountStrategy> combined = new ArrayList<>();
combined.add(new PercentageDiscount(0.9)); // 子折扣1:9折
combined.add(new FixedDiscount(100)); // 子折扣2:减100
Order order3 = new Order(
originalPrice,
new MemberPriceStrategy(),
new CombinedDiscount(combined) // 组合折扣(嵌套子策略)
);
System.out.println("会员价+组合折扣:" + order3.getFinalPrice());
// 计算过程:1000*0.95=950 → 950*0.9=855 → 855-100=755.0
}
}
嵌套关系说明
- 外层策略(
PriceCalculationStrategy)依赖内层策略(DiscountStrategy),形成第一层嵌套。 - 内层策略中的
CombinedDiscount又依赖多个DiscountStrategy,形成第二层嵌套。 - 策略之间通过组合关系实现嵌套,而非继承,符合 "多用组合少用继承" 的设计原则。
优势
- 灵活性:可动态替换外层价格策略和内层折扣策略,且支持无限层级的策略嵌套。
- 可扩展性:新增折扣类型(如满减、第二件半价)只需实现
DiscountStrategy,无需修改现有代码。 - 可读性:每个策略职责单一,嵌套关系通过组合显式表达,逻辑清晰。