大话设计模式读书笔记(二) 策略模式

书中通过一道题目,让"小菜"设计一个商场收银软件,营业员根据客户购买商品的数量及单价,想客户收费。,并且软件可以兼容打折,返点等优惠活动的金额计算。

一开始,小菜使用之前所学的简单工厂模式来制作这个收银软件。

收费父类

public abstract class CashSuper {
	/**
	 * 收费方法
	 * @param money //原价
	 * @return
	 */
	public abstract double acceptCash(double money); 
}
普通收费子类

/**
 * 普通计算类
 *
 */
public class CashNormal extends CashSuper{

	@Override
	public double acceptCash(double money) {
		
		return money;
	}
	
}
打折收费类

//打折类
public class CashRebate extends CashSuper{
	
	private double cashRebate = 1d;//折扣
	
	public CashRebate(double cashRebate) {
		super();
		this.cashRebate = cashRebate;
	}
	@Override
	public double acceptCash(double money) {
		return money*cashRebate;
	}
}

满减收费类

public class CashReturn extends CashSuper{
	private double moneyCondition = 0.0d;//满多少钱开始反
	private double moneyReturn = 0.0d;//反多少钱
	public CashReturn(double moneyCondition, double moneyReturn) {
		super();
		this.moneyCondition = moneyCondition;
		this.moneyReturn = moneyReturn;
	}
	@Override
	public double acceptCash(double money) {
		return money>moneyCondition?
		money-Math.floor(money/moneyCondition)*moneyReturn:money;
	}
}
收费工厂类

//收费工厂
public class CashFactory {
	public static CashSuper createCashSuper(String type){
		CashSuper cs = null;
		switch (type) {
		case "打8折":
			cs=new CashRebate(0.8);
			break;
		case "满300减100":
			cs=new CashReturn(300,100);
			break;
		default:
			cs=new CashNormal();
			break;
		}
		return cs;
	}
}
主方法
public class Main {
	public static void main(String[] args) {
		double totalPrice = 0.0d;//总金额
		String type = "满300减100";
		CashSuper cs =CashFactory.createCashSuper(type);
		double price = 400d;//未打折前金额
		totalPrice+=cs.acceptCash(price);//打折后金额
		System.out.println(totalPrice);
	}
}


但是这里就遇到了我们在学习简单工厂方法时想到的问题,按照大鸟的话来讲;“简单工厂模式虽然也能解决这个问题,但是简单工厂模式只是解决对象的创建问题。而且由于工厂本身包含所有的收费方式,商场可能经常性的更改打折和满减方式,每次修改和扩展收费方式都要修改工厂类,以至于代码需要重新编译部署。这真的是很糟糕的处理方式,不是最好的方法。”


于是,引出了策略模式。。。。


策略模式(Strategy):它定义了算法家族,分别封装起来,让他们之间可以互相替代,此模式让算法的变化,不用影响使用算法的客户。

策略模式结构图



通过使用策略模式,修改代码,将打折,满减等算法,都有Context来配置,于是只需要加一个Context类和改一下主方法。

public class CashContext {
	private CashSuper cashSuper;//收费接口
	public CashContext(CashSuper cashSuper) {
		this.cashSuper = cashSuper;
	}
	
	public double getResult(double money){
		return cashSuper.acceptCash(money);
	}
}
主方法:

public class Main {
	public static void main(String[] args) {
		double totalPrice  =0.0d;//用于小计
		CashContext cc=null;
		String type = "满300减100";
		switch (type) {
		case "满300减100":
			cc=new CashContext(new CashReturn(300, 100));
			break;
		case "打9折":
			cc=new CashContext(new CashRebate(0.9));
			break;
		default:
			cc=new CashContext(new CashNormal());
			break;
		}
		totalPrice+=cc.getResult(400);
		System.out.println(totalPrice);
	}
}
但是这样又需要客户端去判断到底执行什么算法。于是引出了策略模式与简单工厂模式的结合。

于是改造CashContext和主方法

public class CashContext {
	private CashSuper cashSuper;//收费接口
	public CashContext(String type) {
		super();
		switch (type) {
		case "满300减100":
			cashSuper=new CashReturn(300, 100);
			break;
		case "打9折":
			cashSuper=new CashRebate(0.9);
			break;
		default:
			cashSuper=new CashNormal();
			break;
		}
	}
	public double getResult(double money){
		return cashSuper.acceptCash(money);
	}
}
主方法:

public class Main {
	public static void main(String[] args) {
		double totalPrice  =0.0d;//用于小计
		CashContext cc=null;
		String type = "满300减100";
		cc = new CashContext(type);
		totalPrice+=cc.getResult(400);
		System.out.println(totalPrice);
	}
}

对比简单工厂模式和策略模式与工厂模式的结合, 简单工厂模式需要客户端认识两个类CashSuper和CashFactory,而策略模式和工厂模式的结合,客户端只需要认识Context一个类就可以了,代码的耦合性进一步降低。



策略模式解析:

策略模式优点:

1、它可以以相同的方式来调用所有的方法,减少了各种算法类之间的耦合。例如上面例子中,无论是打折,还是满减,客户端调用的都是Context.getResult();。

  2、简化了单元测试,每个算法都有自己的类,可以通过自己的接口进行单元测试。

3、当一个算法出现问题是,对其他算法没有影响。

策略模式应用场景:

只要在分析过程中听到有不同时间应用不同的业务规则,就可以考虑应用策略模式来处理这种变化。


策略模式的重心

  策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。

策略模式的缺点

  (1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况。

  (2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值