《大话设计模式》Java实现----策略模式

摘要:

        原著:程杰。本文是在原文学习的基础上对原文的demo进行Java的翻译,是根据自己的理解实现的,欢迎各位交流感受。

       主要案例,策略模式实现商场收银。假如说这是 一道面试题,如果让我去做的话,说实话,我不会想到会用设计者模式去做,因为感觉只要是实现了最终的目的就可以了,干嘛非要弄得这么麻烦。但其实做完之后会发现差别其实是挺大的。平时在写业务代码的时候也是一样,不单单是需要将当前的业务实现了就可以,还要考虑代码的可读性和后期的可维护性,要不然估计就算想离职老板都不会让走吧,哈哈。

       demo介绍:实现一个商场收银功能的计算器,该计算器可以实现商品的打折,满减等优惠。

       在实现上,通过一个上下文类实现对简单工厂类的封装,对程序中的各个类进行解耦合,降低各类之间的关联性,好处就是,当有一天需求变化的时候,可以尽可能少的去修改代码。废话不多说,上代码:

/**
 * 收费父类
 * 
 * @author weiming.liu
 * @Date 2019年5月11日 下午8:41:35
 */
public abstract class CashSuper {

	/**
	 * 计算金额
	 * 
	 * @param money
	 * @return
	 */
	public abstract String acceptCash(BigDecimal money);
}
/**
 * 正常收费
 * 
 * @author weiming.liu
 * @Date 2019年5月11日 下午9:18:52
 */
public class CashNormal extends CashSuper {

	@Override
	public String acceptCash(BigDecimal money) {
		return money.toString();
	}

}
/**
 * 打折收费
 *
 * @author weiming.liu
 * @Date 2019年5月11日 下午8:46:49
 */
public class CashRebate extends CashSuper {

	private int moneyRebate = 10; // 默认为不打折
	
	public CashRebate(int moneyRebate) {
		if (moneyRebate > 10 || moneyRebate <= 0) {
			moneyRebate = 10;
		}
		this.moneyRebate = moneyRebate;
	}

	@Override
	public String acceptCash(BigDecimal money) {
		return money.multiply(new BigDecimal(moneyRebate).divide(new BigDecimal(10))).toString();
	}

}
/**
 * 满减计算
 * 
 * @author weiming.liu
 * @Date 2019年5月11日 下午9:22:43
 */
public class CashReturn extends CashSuper {

	private BigDecimal moneyCondition = new BigDecimal(0);
	private BigDecimal moneyReturn =  new BigDecimal(0);
	
	
	public CashReturn(double moneyCondition, double moneyReturn) {
		if (moneyCondition < moneyReturn) {
			System.out.println("你傻啊!");
		}
		this.moneyCondition = new BigDecimal(moneyCondition);
		this.moneyReturn = new BigDecimal(moneyReturn);
	}

	@Override
	public String acceptCash(BigDecimal money) {
		BigDecimal result = money;
		if (moneyCondition.compareTo(money) < 1) { // 如果满减金额小于小于等于付款金额
			result = money.subtract(money.divide(moneyCondition,0, BigDecimal.ROUND_DOWN).multiply(moneyReturn));
		}
		return result.toString();
	}

}
/**
 * 费用计算工厂类
 * @author weiming.liu
 * @Date 2019年5月11日 下午9:13:27
 */
public class CashFactory {

	
	public static CashSuper createCashAccept(String type){
		CashSuper cs = null;
		
		switch (type) {
		case "正常收费":
			cs = new CashNormal();
			break;
		case "满300减100":
			cs = new CashReturn(300, 100);
			break;
		case "打八折":
			cs = new CashRebate(8);
			break;
		default:
			cs = new CashNormal();
			break;
		}
		return cs;
	}
}
/**
 * 上下文关联
 * 
 * @author weiming.liu
 * @Date 2019年5月11日 下午9:23:20
 */
public class CashContext {

	private String type = "";
	
	public CashContext(String type) {
		this.type = type;
	}

	public String getResult(BigDecimal money){
		CashSuper cs = CashFactory.createCashAccept(type);
		return cs.acceptCash(money);
	}
	
}
/**
 * 金额计算客户端
 * 
 * @author weiming.liu
 * @Date 2019年5月11日 下午9:33:49
 */
public class CashClient {

	public static void main(String[] args) {
		CashContext csuper = new CashContext("正常收费");
		String total = csuper.getResult(new BigDecimal(1000));
		System.out.println(total);
	}
}

       在上述实现中,定义计算父类CashSuper.java,对于原价、打折和满减都继承该父类,并通过工厂类CashFactory.java去实例化计算的实现类,最后通过在客户端程序中引用上下文类CashContext.java去创建具体的计算类去实现折扣的计算。

       在实现上,使用了Bigdecimal类替换原有的doulbl类,因为double类在计算的时候容易导致精度错乱问题,所以在在实现上采用了Bigdecimal类。

       看完上述代码,你肯定也会发现,在代码中只有打八折,那么如果打九折或者打半折如何处理呢?难道把所有的折扣都维护一遍,然后用switch判断一遍?对于这个问题,如果各位有实现的方法可以留言交流。

书中摘抄:

      1.策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现方式不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合;

      2.策略模式就是用来封装方法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

 

 

 

你可能感兴趣的:(Java例程)