java设计模式————策略模式,手写手机支付方式

策略模式

是定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。

可以避免多重分之的if...else..和switch语句

应用场景

1.假如系统中有很多类,而他们的区别仅仅在于他们的行为不同。

2.一个系统需要动态的在几种算法中选择一种。

例子,京东现在要搞促销,需要几种优惠活动,那我们可以用策略模式来写。

/**
 * @Author Darker
 * @Descrption 京东促销活动优惠方式接口
 * @Date : Created in 13:54 2020-3-12
 */
public interface JDactivity {

    //促销方式
    /**
     * 1.原价
     * 2.现金返现
     * 3.优惠券减免
     * 4.赠送实物
     *
     */
    void activity();
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 13:57 2020-3-12
 */
public class EmptyActivity implements JDactivity{
    @Override
    public void activity() {
        System.out.println("原价");
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 13:59 2020-3-12
 */
public class CashBackActivity implements JDactivity{
    @Override
    public void activity() {
        System.out.println("购物直接返现,返回现金到京东账号");
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 13:57 2020-3-12
 */
public class CouponsActivity implements JDactivity{
    @Override
    public void activity() {
        System.out.println("领取优惠券,购物减免价格");
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 14:00 2020-3-12
 */
public class GiftActivity implements JDactivity {
    @Override
    public void activity() {
        System.out.println("购物赠送礼品");
    }
}

/**
 * @Author Darker
 * @Descrption 活动策略规则
 * @Date : Created in 14:02 2020-3-12
 */
public class ActivityStrategy {

    //把优惠活动作为成员变量,new哪一种子类就是哪一种优惠
    JDactivity jDactivity;

    public ActivityStrategy(JDactivity jDactivity){
        this.jDactivity = jDactivity;
    }

    public void execute(){
        jDactivity.activity();
    }
}


运行试一试

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 14:04 2020-3-12
 */
public class StrategyTest {
    public static void main(String[] args) {
        //6.18购物活动
        ActivityStrategy activity618 = new ActivityStrategy(new CashBackActivity());
        activity618.execute();
        //双11购物优惠
        ActivityStrategy activity1111 = new ActivityStrategy(new CouponsActivity());
        activity1111.execute();
    }
}

这就是最简单的策略模式的运用了,定义了一个算法家族(优惠家族),动态的选择一种算法(优惠)。

但是!但是!但是!!!

到了用户调用层,你会发现你又要if...else..;比如下面这样,通过前端传来的字段来生成你要的优惠活动,既然说策略模式避免if...esle..,现在不还是用了嘛,当然,一种不行可以玩结合不是,看到下面代码,活脱脱一个简单工厂模式嘛,我们完全可以改成工厂模式,用工厂来生成这个策略,顺便把工厂变成单例,还提高效率。

所以,我们给他加上代码

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 14:40 2020-3-12
 */
public  class ActivityStrategyFactory {

    //构造方法私有化
    private  ActivityStrategyFactory(){};

    //饿汉式单例
    private static ActivityStrategyFactory activityStrategyFactory = new ActivityStrategyFactory();

    private static Map<String,JDactivity> iocMap = new HashMap<>();

    static {
        iocMap.put(ActivityKey.COUPON,new CouponsActivity());
        iocMap.put(ActivityKey.CASHBACK,new CashBackActivity());
        iocMap.put(ActivityKey.GIFT,new GiftActivity());
    }

    //无优惠
    private static final ActivityStrategy  NON_ACTIVITY_STRATEGY = new ActivityStrategy(new EmptyActivity());

    //全局唯一工厂路口
    public static ActivityStrategyFactory getInstance(){
        return activityStrategyFactory;
    }

    //工厂生成相应策略的活动
    public ActivityStrategy getActivityStrategy(String activity){
        ActivityStrategy activityStrategy = new ActivityStrategy(iocMap.get(activity));
        return activityStrategy == null ? NON_ACTIVITY_STRATEGY:activityStrategy;
    }

    //活动字符串,约定>配置
    private interface ActivityKey{
        String COUPON = "COUPON";
        String CASHBACK = "CASHBACK";
        String GIFT = "GIFT";
    }
}

 运行看看

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 14:04 2020-3-12
 */
public class StrategyTest {
    public static void main(String[] args) {

        //前端传来的活动key
        String activityKey = "CASHBACK";
        //生成策略工厂
        ActivityStrategyFactory strategyFactory = ActivityStrategyFactory.getInstance();
        ActivityStrategy activityStrategy = strategyFactory.getActivityStrategy(activityKey);
        activityStrategy.execute();

    }
}

你看这样就对客户端调用非常友好了不是,而且当我们增加活动的时候只需要去添加一点配置字段就行了,改起来也很快。

我们再来看看这个类图:

这样就很清晰了,我们有4个优惠策略,通过活动策略来生成对应的策略,同时用工厂来生产策略。 

是不是还不过瘾,那我们再来复现一个日常中经常使用的功能,手机支付,一个非常经典的策略模式。

/**
 * @Author Darker
 * @Descrption 支付抽象类,包含公共判断逻辑
 * @Date : Created in 16:12 2020-3-12
 */
public abstract class Paymet {

    public  abstract String getKeyName();

    //查询余额
    protected abstract double queryBalance(String uid);

    //公用支付逻辑
    public MsgResult pay(String uid,double amount){
        if(queryBalance(uid)<amount){
            return new MsgResult(500,"支付失败","余额不足");
        }else{
            return new MsgResult(200,"支付成功","支付金额"+amount);
        }
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 16:11 2020-3-12
 */
public class Alipay extends Paymet{
    @Override
    public String getKeyName() {
        return "支付宝";
    }

    @Override
    protected double queryBalance(String uid) {
        return 250;
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 16:16 2020-3-12
 */
public class JDpay extends Paymet {
    @Override
    public String getKeyName() {
        return "京东白条";
    }

    @Override
    protected double queryBalance(String uid) {
        return 500;
    }
}

/**
 * @Author Darker
 * @Descrption
 * @Date : Created in 16:18 2020-3-12
 */
public class WechatPay extends Paymet {
    @Override
    public String getKeyName() {
        return "微信支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 700;
    }
}

/**
 * @Author Darker
 * @Descrption 订单
 * @Date : Created in 15:45 2020-3-12
 */
@Data
@AllArgsConstructor
public class Order {
    private String uid;
    private String orderId;
    private Double amount;

    public MsgResult pay(String payKey){
        Paymet paymet = PayStrategy.getInstance(payKey);
        MsgResult result = paymet.pay(orderId, amount);
        return result;
    }

}

/**
 * @Author Darker
 * @Descrption 返回包装类
 * @Date : Created in 16:07 2020-3-12
 */
@Data
@AllArgsConstructor
public class MsgResult {

    private int code;
    private Object data;
    private String msg;

    @Override
    public String toString() {
        return "支付状态:[" + code +"]," + msg +",交易详情"+ data;
    }
}


/**
 * @Author Darker
 * @Descrption 支付策略
 * @Date : Created in 16:25 2020-3-12
 */
public class PayStrategy {
    public static final String ALI_PAY = "Alipay";
    public static final String JD_PAY = "Jdpay";
    public static final String WECHAT_PAY = "Wechatpay";
    public static final String DEFAULT_PAY = ALI_PAY;

    private static Map<String, Paymet> payStrategy =new HashMap<>();

    static {
        payStrategy.put(ALI_PAY,new Alipay());
        payStrategy.put(JD_PAY,new JDpay());
        payStrategy.put(WECHAT_PAY,new WechatPay());
    }

    public static Paymet getInstance(String payKey){
        Paymet paymet = payStrategy.get(payKey) ;
        return paymet == null ? payStrategy.get(DEFAULT_PAY):paymet;
    }
}


/**
 * @Author Darker
 * @Descrption 测试
 * @Date : Created in 16:21 2020-3-12
 */
public class payStrategyTest {
    public static void main(String[] args) {
        String payKey = "Jdpay";
        String payKey2 = "Wechatpay";
        
        //用户提交了一个订单
        Order order = new Order("1", "2020031200000000", 570.00);

        //用户选择支付方式,京东白条
        MsgResult result = order.pay(payKey);
        System.out.println(result);

        //用户选择支付方式,微信支付
        MsgResult result2 = order.pay(payKey2);
        System.out.println(result2);
    }
}

 来看看,这是不是就是我们实际上支付使用的方式呢。

好,最后,我们再来说说jdk在哪里用了策略模式呢,答案就是Comparator,比较器,我们经常用比较器来排序,这个比较器里面有很多的算法,我们可以随意选择自己喜欢的策略来排序,非常经典。

同样,在spring中也用到了策略模式,在类的初始化的时候它会选择是用jdk的方式还是cglib的方式。

总结:

优点:

1.策略模式符合开闭原则

2.避免使用多重条件转移语句,如if...else.....

3.使用策略模式可以提高算法的保密性和安全性

缺点:

1.客户端必须知道所有的策略,并且自行决定使用哪一个策略类。

2.代码中会产生非常多的策略类,增加维护难度。

发布了27 篇原创文章 · 获赞 1 · 访问量 3641

猜你喜欢

转载自blog.csdn.net/qq_40111437/article/details/104817532