-
怎么把策略模式和工廠模式結合起來使用
如果大家對策略模式和工廠模式不是很了解的話可以先看前面文章
策略模式: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()); } }
執行結果

小結:
策略模式:負責對扣款封裝,保證兩個策略自由切換,以后增加策略也很容易
工廠模式:修正策略模式必須對外暴露問題,由工廠模式產生一個具體策略對象