设计模式-策略模式和工厂模式结合使用
-
怎么把策略模式和工厂模式结合起来使用
如果大家对策略模式和工厂模式不是很了解的话可以先看前面文章
策略模式:https://www.jianshu.com/p/958281936901
工厂模式:https://www.jianshu.com/p/9078481e00c6
大家可能都用过微信支付,在使用微信支付付钱时候:
1、当我们的付款金额大于我们的余额时,会让我们使用银行卡支付,
2、余额充足的时候会让我们优先使用余额里面的钱
扣款策略一:
余额(blance) >= 付款金额(tradeAmout) 使用余额
扣款策略二:
余额(blance) < 付款金额(tradeAmout) 使用银行卡
很明显这是一个策略模式的实际应用,但是你还记得策略模式的缺陷吗?它的具体策略必须暴露出去,而且还要由上层模块初始化,这不适合,与迪米特法则不符( 迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。注:摘自百度百科,这个迪米特法则下次再细讲)冲突。高层模块对底层模块仅仅在接触层次上,而不应该是耦合关系。问题出了,我们应该想办法解决,正好工厂模式可以帮我们解决这个问题。但是引入工厂模式也有问题,工厂方法要指定一个类,它才能生产对象,我们用枚举来完成。
首先我们先建两个实体类WxBlance和WxTrade
import java.math.BigDecimal;
/**
* @author shuliangzhao
* @Title: WxBlance
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:50
*/
public class WxBlance {
//余额
private BigDecimal blance;
public BigDecimal getBlance() {
return blance;
}
public void setBlance(BigDecimal blance) {
this.blance = blance;
}
}
import java.math.BigDecimal;
/**
* @author shuliangzhao
* @Title: Trade
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:51
*/
public class WxTrade {
private BigDecimal tradeAmout;
private String tradeNo;
private BigDecimal userAmout;
public BigDecimal getUserAmout() {
return userAmout;
}
public void setUserAmout(BigDecimal userAmout) {
this.userAmout = userAmout;
}
public String getTradeNo() {
return tradeNo;
}
public void setTradeNo(String tradeNo) {
this.tradeNo = tradeNo;
}
public BigDecimal getTradeAmout() {
return tradeAmout;
}
public void setTradeAmout(BigDecimal tradeAmout) {
this.tradeAmout = tradeAmout;
}
}
扣款策略接口
/**
* @author shuliangzhao
* @Title: Deduction
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:53
*/
public interface Deduction {
public boolean exec(WxBlance wxBlance,WxTrade wxTrade);
}
扣款策略一
/**
* @author shuliangzhao
* @Title: BlanceDeduction
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:54
*/
public class BlanceDeduction implements Deduction {
@Override
public boolean exec(WxBlance wxBlance, WxTrade wxTrade) {
if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) >= 0) {
wxTrade.setUserAmout(wxBlance.getBlance());
}
return true;
}
}
扣款策略二
/**
* @author shuliangzhao
* @Title: IdCardDeduction
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:54
*/
public class IdCardDeduction implements Deduction {
@Override
public boolean exec(WxBlance wxBlance, WxTrade wxTrade) {
if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) < 0) {
wxTrade.setUserAmout(wxTrade.getTradeAmout());
}
return true;
}
}
扣款策略封装
/**
* @author shuliangzhao
* @Title: DedutionContext
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/28 23:58
*/
public class DedutionContext {
private Deduction deduction;
public DedutionContext(Deduction deduction) {
this.deduction = deduction;
}
public boolean exec(WxBlance wxBlance,WxTrade wxTrade) {
return deduction.exec(wxBlance,wxTrade);
}
}
典型的策略上下文。策略模式的缺陷把所有策略类都暴露出去,怎么修改呢?使用工厂模式根据映射产生策略对象
策略枚举
/**
* @author shuliangzhao
* @Title: StrategyEnum
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/29 0:00
*/
public enum StrategyEnum {
BlanceDeduction("com.sl.factorystrategy.BlanceDeduction"),
IdCardDeduction("com.sl.factorystrategy.IdCardDeduction");
String value = "";
private StrategyEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
策略工厂
/**
* @author shuliangzhao
* @Title: StrategyFactory
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/29 0:03
*/
public class StrategyFactory {
public static Deduction getDeduction(StrategyEnum strategyEnum) {
Deduction deduction = null;
try {
deduction = (Deduction)Class.forName(strategyEnum.getValue()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return deduction;
}
}
扣款调用类
/**
* @author shuliangzhao
* @Title: DeductionFacade
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/29 0:06
*/
public class DeductionFacade {
//扣款
public static void deduct(WxBlance wxBlance,WxTrade wxTrade) {
StrategyEnum strate = getStrate(wxBlance, wxTrade);
Deduction deduction = StrategyFactory.getDeduction(strate);
deduction.exec(wxBlance,wxTrade);
}
//获取扣款策略
private static StrategyEnum getStrate(WxBlance wxBlance,WxTrade wxTrade) {
if (wxBlance.getBlance().compareTo(wxTrade.getTradeAmout()) < 0) {
return StrategyEnum.IdCardDeduction;
}else {
return StrategyEnum.BlanceDeduction;
}
}
}
调用客户端client
/**
* @author shuliangzhao
* @Title: Client
* @ProjectName design-parent
* @Description: TODO
* @date 2019/5/29 0:10
*/
public class Client {
public static void main(String[] args) {
WxTrade wxTrade = new WxTrade();
wxTrade.setTradeAmout(new BigDecimal("1000"));
WxBlance wxBlance = new WxBlance();
wxBlance.setBlance(new BigDecimal("999"));
DeductionFacade.deduct(wxBlance,wxTrade);
System.out.println(wxTrade.getUserAmout());
}
}
执行结果
小结:
策略模式:负责对扣款封装,保证两个策略自由切换,以后增加策略也很容易
工厂模式:修正策略模式必须对外暴露问题,由工厂模式产生一个具体策略对象