设计模式十三(策略模式)

前言

在平时开发工作中,相信大家经常会见到大量的 if…else…或者 switch…case…等代码,让代码显得很臃肿,不美观,那么有什么好的办法可以来进行优化呢?无可厚非,策略模式就能很完美的解决此类问题,可以使我们的代码显得更加高大上,下面来学习一下策略模式到底是怎么玩的。

定义

策略模式( Strategy Pattern)又叫政策模式( Policy Pattermn),它是将定义的算法家族分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。属于行为型模式。

应用场景

策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现。

策略模式在生活场景中应用也非常多。比如一个人的交税比率与他的工资有关,不同的工资水平对应不同的税率。再比如我们在互联网移动支付的大背景下,每次下单后付款前,需要选择支付方式。
在这里插入图片描述
首先来看一下策略模式的基本 UML 类图:
在这里插入图片描述
我们可以看到,策略模式主要包含三种角色:

  • 上下文角色(Context): 用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略算法的直接访问,封装可能存在的变化;
  • 抽象策略角色(Strategy): 规定策略或算法的行为;
  • 具体策略角色(ConcreteStrategy): 具体的策略或算法实现。
注意:策略模式中的上下文环境(Context),其职责本来是隔离客户端与策略类的耦合,让客户端完全与上下文环境沟通,无须关心具体策略。
用策略模式实现选择支付方式的业务场景

我们来举一个案例,相信大家都用过支付宝支付、微信支付、京东白条支付等支付方式,一个常见的应用的场景,就是大家在下单的时候会提示选择支付方式,如果用户未选择,系统也会默认好推荐的支付方式来进行结算。下面我们用策略模式来完成这个场景。

先定义一下我们的返回结果对象:

public class MsgResult {
    private int code;
    private Object data;
    private String msg;

    public MsgResult(int code, String msg, Object data) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MsgResult{" +
                "code=" + code +
                ", data=" + data +
                ", msg='" + msg + '\'' +
                '}';
    }
}

创建支付抽象类 Payment,来定义好支付规范与支付逻辑,如下:

public abstract class Payment {

	/**
	 * 支付方式的名称
	 * @return
	 */
    public abstract String getName();

	/**
	 * 通用逻辑放到抽象类里面实现
	 * @param uid
	 * @param amount
	 * @return
	 */
    public MsgResult pay(String uid, double amount){
        //余额是否足够
        if(queryBalance(uid) < amount){
            return new MsgResult(500,"支付失败","余额不足");
        }
        //扣减对应金额
		boolean res = deductionAmount(amount);
        if (res) {
			return new MsgResult(200,"支付成功","支付金额" + amount);
		} else {
			return new MsgResult(400,"支付失败,扣减余额异常","支付金额" + 0);
		}
    }

	/**
	 * 查询用户余额
	 * @param uid
	 * @return
	 */
	protected abstract double queryBalance(String uid);

	/**
	 * 扣减余额
	 * @param amount
	 * @return
	 */
	protected abstract boolean deductionAmount(double amount);
}

分别创建具体的支付方式,AliPay:

public class AliPay extends Payment {
	@Override
	public String getName() {
		return "支付宝";
	}

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

	@Override
	protected boolean deductionAmount(double amount) {
		//TODO 具体的扣减余额操作
		return true;
	}
}

创建微信支付,WechatPay:

public class WechatPay extends Payment {
    
	@Override
	public String getName() {
        return "微信支付";
    }

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

	@Override
	protected boolean deductionAmount(double amount) {
		//TODO 具体的扣减余额操作
    	return true;
	}
}

创建京东白条支付,JDPay :

public class JDPay extends Payment {
   
	@Override
	public String getName() {
        return "京东白条";
    }

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

	@Override
	protected boolean deductionAmount(double amount) {
		//TODO 具体的扣减余额操作
		return true;
	}
}

创建银联支付,UnionPay :

public class UnionPay extends Payment {
    
	@Override
	public String getName() {
        return "银联支付";
    }

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

	@Override
	protected boolean deductionAmount(double amount) {
		//TODO 具体的扣减余额操作
		return true;
	}
}

创建支付策略管理类:PayStrategy :

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 UNION_PAY = "UnionPay";
	public static final String DEFAULT_PAY = ALI_PAY;

	private static Map<String, Payment> strategy = new HashMap<>();

	static {
		strategy.put(ALI_PAY, new AliPay());
		strategy.put(JD_PAY, new JDPay());
		strategy.put(WECHAT_PAY, new WechatPay());
		strategy.put(UNION_PAY, new UnionPay());
	}

	public static Payment get(String payKey) {
		if (!strategy.containsKey(payKey)) {
			return strategy.get(DEFAULT_PAY);
		}
		return strategy.get(payKey);
	}
}

创建订单类,Order :

public class Order {

	private String uid;
	private String orderId;
	private double amount;

	public Order(String uid, String orderId, double amount) {
		this.uid = uid;
		this.orderId = orderId;
		this.amount = amount;
	}

	/**
	 * 默认的支付方式
	 *
	 * @return
	 */
	public MsgResult pay() {
		return pay(PayStrategy.DEFAULT_PAY);
	}

	/**
	 * 指定支付方式
	 *
	 * @param payKey
	 * @return
	 */
	public MsgResult pay(String payKey) {
		Payment payment = PayStrategy.get(payKey);
		System.out.println("欢迎使用" + payment.getName());
		System.out.println("本次交易金额为" + amount + ",开始扣款");
		return payment.pay(uid, amount);
	}
}

下面来进行测试:

public static void main(String[] args) {
		Order order = new Order("1", "2021051001000323", 324.5);
		System.out.println(order.pay(PayStrategy.UNION_PAY));
	}

通过上面的案例,相信小伙伴们已经深刻理解了策略模式的使用。

策略模式的优缺点

优点:

  • 策略模式,符合开闭原则;
  • 避免使用多重条件转移语句,如 if…else…语句;
  • 使用策略模式,可以提高算法的保密性和安全性;

缺点:

  • 客户端必须知道所有策略,并且自行决定使用哪一策略;
  • 代码中会产生非常多的策略类,增加维护难度;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值