策略模式(StrategyPattern)是指定义了算法家族、分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
应用场景1、假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。 2、一个系统需要动态地在几种算法中选择一种。
优点1、策略模式符合开闭原则。 2、避免使用多重条件转移语句,如if…else…语句、switch语句 3、使用策略模式可以提高算法的保密性和安全性。
缺点1、客户端必须知道所有的策略,并且自行决定使用哪一个策略类。 2、代码中会产生非常多策略类,增加维护难度。
下面请看案例 模拟一个场景,某商场正在进行活动,活动分为了三种,返现、团购、折扣。客户可以自行选择哪一种优惠。
1.定义一个公共的策略抽象
//优惠策略抽象
public interface PromotionStrategy {
//优惠活动,公共行为
void doPromotion();
}
2.分别写出上面三种策略具体行为。
//优惠券活动
public class CouponStrategy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("领取优惠券,所有商品8折优惠");
}
}
//返现活动
public class CashbackStrtegy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("购满200元,返现20元到支付账号");
}
}
//团购活动
public class GroupbuyStrategy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("团购活动,满10人享受团购价");
}
}
//无优惠
public class EmptyStrategy implements PromotionStrategy{
@Override
public void doPromotion() {
System.out.println("没有活动力度!");
}
}
3.定义活动规则并发布
//活动规则
public class PromotionActivity {
private PromotionStrategy promotionStrategy;
public PromotionActivity(PromotionStrategy promotionStrategy){
this.promotionStrategy = promotionStrategy;
}
//发布活动
public void execute(){
this.promotionStrategy.doPromotion();
}
}
现在展示两种不同的写法来比较一下。 测试 1.过去使用的写法,首先创建一个对象在,在构造函数中传递一个优惠类型来指定某种优惠。这种显然是最不提倡的。
//一般写法
public static void main(String[] args) {
//优惠券活动
PromotionActivity activity = new PromotionActivity(new CouponStrategy());
activity.execute();
//返现活动
PromotionActivity activity1 = new PromotionActivity(new CashbackStrtegy());
activity1.execute();
}
//输出结果:
领取优惠券,所有商品8折优惠
购满200元,返现20元到支付账号
由于活动的选择是根据不同的需求的对促销策略进行动态选择的,并不会一次执行多个优惠,所以上面那种情况在实际场景中几乎用不着,我们一般会使用以下这种写法。
2.客户选择策略
public static void main(String[] args) {
PromotionActivity promotionActivity = null;
//客户选择的优惠类型
String promotionKey = "COUPON";
//此处感觉像什么设计模式? ---------》简单工厂
if(promotionKey.equals("COUPON")){ //优惠券
promotionActivity = new PromotionActivity(new CouponStrategy());
}else if(promotionKey.equals("CASHBACK")){ //返现
promotionActivity = new PromotionActivity(new CashbackStrtegy());
}
promotionActivity.execute();
}
//输出结果
//领取优惠券,所有商品8折优惠
这样改写之后,我们满足了业务需求,可以可以根据自己的需求选择不同的优惠策略了。但是也并不是提倡的选择它也存在弊端:随着时间的业务累计,我们的促销活动会越来越多,于是我们每次增加活动时都得不停的修改逻辑和测试,判断的逻辑也会越来越复杂。 如何解决?------》结合单例和工厂模式来解决:有兴趣的朋友可以了解一下本分类下的文章(单例:单例 | 工厂:工厂)
定义一个工厂类,在这里我就不定义接口了,直接写类来模拟 策略工厂PromotionStrategyFactory 类
public class PromotionStrategyFactory {
//注册式单例
private static Map PROOTION_STRATEGY_MAP = new HashMap();
//模拟加载资源
static {
PROOTION_STRATEGY_MAP.put(PromotionKey.COUPON,new CouponStrategy());
PROOTION_STRATEGY_MAP.put(PromotionKey.CASHBACK,new CashbackStrtegy());
PROOTION_STRATEGY_MAP.put(PromotionKey.GROUPBUY,new GroupbuyStrategy());
}
//构造方法
private PromotionStrategyFactory(){
}
//无活动对象
private static final PromotionStrategy NON_PROMOTION = new EmptyStrategy();
//定义活动类型
private interface PromotionKey{
String COUPON = "COUPON";
String CASHBACK = "CASHBACK";
String GROUPBUY = "GROUPBUY";
}
//提供对外方法
public static PromotionStrategy getPromotionStrategy(String promotionkey){
return promotionkey == null || promotionkey.equals("") ? NON_PROMOTION: PROOTION_STRATEGY_MAP.get(promotionkey);
}
}
测试代码
public static void main(String[] args) {
String promotionKey = "GROUPBUY";
PromotionActivity promotionActivity =
new PromotionActivity(PromotionStrategyFactory.getPromotionStrategy(promotionKey));
promotionActivity.execute();
//增加一个优惠
}
这样优化了之后,每次增加新的活动不会在影响原来的代码逻辑。只需要工厂中进行添加即可。
再来模拟一个在实际开发中遇到的场景。
比如我们在买东西时候的支付时候得选择,可以选择支付宝、微信、京东、银联等方法来选择付款方式,下面我们就来模拟一下此类场景 1.定义一个抽象的类表示是哪一种付款类型对象(支付宝或微信还是京东又或者银联。 - -!不想落下其中一个,显得孤独。) 疑问:为什么定义成抽象类? 答:因为不管是上述其中任何一种支付类型,他们对于顾客来说支付类型都是相似的。扫码->余额是否足够->成功或者失败所以他们是一个公共的动作和相似的逻辑。因此在这定义成抽象类来约束规范和逻辑
//Payment 抽象类。
public abstract class Payment {
//抽象方法,支付类型
public abstract String getName();
//账户余额,方法根据uid查询对应账户余额,在这里就简写了。
protected abstract double quetyBalance(String uid);
//支付方法
public MsgResult pay(String uid,double amount){
if(quetyBalance(uid) 状态码:500, 支付金额:余额不足, 支付结果:支付失败
欢迎使用【京东白条】
本次交易:499.6, 开始扣款...
支付状态---->状态码:200, 支付金额:支付金额:499.6, 支付结果:支付成功
我们来看一看类图 到此本篇就介绍介绍了,希望各位看过的伙伴们如果发现了问题能够及时批评指正,在此感谢。