Java设计模式——策略模式
在软件系统可能需要根据不同的情境或条件使用不同的算法或行为,但是这些算法的选择和使用可能会频繁变化。在一个类中或许可以通过一系列的条件判断去区分算法的使用,但是这就会导致代码的臃肿不堪,难以维护和扩展。这时我们需要一种方式来灵活地选择和切换不同的算法。这时就可以考虑策略模式,它的主要优点是实现了算法的解耦,使得算法可以独立于客户端而变化。它提高了代码的可维护性和扩展性,因为新的策略可以很容易地添加到系统中。然而策略模式也可能导致类的数量增加,因为每个算法都需要一个对应的策略类。所以要根据类的数量与灵活性来选择是否使用策略模式。
一、接口方式实现
假定一个促销活动方案例子
/*** 抽象促销策略*/
public interface IPromotionStrategy {void doPromotion();
}/*** 团购优惠策略*/
public class GroupBuyStrategy implements IPromotionStrategy {@Overridepublic void doPromotion() {System.out.println("团购优惠");}
}/*** 返现促销策略*/
public class CashbackStrategy implements IPromotionStrategy {@Overridepublic void doPromotion() {System.out.println("返现促销");}
}/*** 优惠卷抵扣策略*/
public class CouponsStrategy implements IPromotionStrategy {@Overridepublic void doPromotion() {System.out.println("优惠卷抵扣");}
}/*** 无优惠策略*/
public class EmptyStrategy implements IPromotionStrategy {@Overridepublic void doPromotion() {System.out.println("无优惠");}
}/*** 促销活动方案*/
public class PromotionActivity {private IPromotionStrategy promotionStrategy;public PromotionActivity(IPromotionStrategy promotionStrategy) {this.promotionStrategy = promotionStrategy;}public void execute() {promotionStrategy.doPromotion();}
}
可结合工厂模式来管理策略
/*** 促销策略工厂*/
public class PromotionStrategyFactory {private static final Map<String, IPromotionStrategy> strategyMap = new HashMap<>();private static final IPromotionStrategy EMPTY = new EmptyStrategy();private PromotionStrategyFactory() {}static {strategyMap.put("COUPONS", new CouponsStrategy());strategyMap.put("CASHBACK", new CashbackStrategy());strategyMap.put("GROUPBUY", new GroupBuyStrategy());}public static IPromotionStrategy getPromotionStrategy(String key) {return strategyMap.get(key) == null ? EMPTY : strategyMap.get(key);}public static Set<String> getPromotionStrategyKeys() {return strategyMap.keySet();}}
编写测试用例
/*** 策略模式-促销活动方案测试*/@Testpublic void testPromotionActivity() {PromotionActivity activity = new PromotionActivity(new CouponsStrategy());PromotionActivity activity1 = new PromotionActivity(new CashbackStrategy());activity.execute();activity1.execute();}/*** 策略模式-促销活动方案(增强版)测试*/@Testpublic void testPromotionActivityUp() {Set<String> strategyKeys = PromotionStrategyFactory.getPromotionStrategyKeys();IPromotionStrategy strategy = PromotionStrategyFactory.getPromotionStrategy("COUPONS");strategy.doPromotion();}
二、抽象类方式实现
假定一个支付方式选择例子
/*** 抽象支付类*/
public abstract class Payment {public abstract String getName();public ResultMsg pay(String uid, double amount) {if (queryBalance(uid) < amount) {return new ResultMsg(500, "支付失败", "余额不足");}return new ResultMsg(200, "支付成功", "支付金额:" + amount);}protected abstract double queryBalance(String uid);
}/*** 订单类*/
@AllArgsConstructor
public class Order {private String uid;private String orderId;private double amount;public ResultMsg pay() {return pay(PayStrategy.DEFAULT_PAY);}public ResultMsg pay(String key) {Payment payment = PayStrategy.get(key);System.out.println("欢迎使用" + payment.getName() + "支付");System.out.println("本次交易金额为" + amount + "元,开始交易扣款");return payment.pay(uid, amount);}
}/*** 支付宝*/
public class AliPay extends Payment {@Overridepublic String getName() {return "支付宝";}@Overrideprotected double queryBalance(String uid) {return 500;}
}/*** 银联支付*/
public class UnionPay extends Payment {@Overridepublic String getName() {return "银联";}@Overrideprotected double queryBalance(String uid) {return 300;}
}/*** 微信支付*/
public class WechatPay extends Payment {@Overridepublic String getName() {return "微信支付";}@Overrideprotected double queryBalance(String uid) {return 250;}
}/*** 支付策略*/
public class PayStrategy {public static final String ALI_PAY = "AliPay";public static final String WECHAT_PAY = "WechatPay";public static final String UNION_PAY = "UnionPay";public static final String DEFAULT_PAY = "AliPay";private static final Map<String, Payment> paymentMap = new HashMap<>();static {paymentMap.put(ALI_PAY, new AliPay());paymentMap.put(WECHAT_PAY, new WechatPay());paymentMap.put(UNION_PAY, new UnionPay());paymentMap.put(DEFAULT_PAY, new AliPay());}public static Payment get(String key) {if (!paymentMap.containsKey(key)) {return paymentMap.get(DEFAULT_PAY);}return paymentMap.get(key);}
}
编写测试用例
/*** 策略模式-支付选择*/@Testpublic void testPayChoose() {Order order = new Order("123", "20220719PAY01", 1000);ResultMsg pay = order.pay(PayStrategy.ALI_PAY);System.out.println(pay);}