就本身實際產品中用的的模式進行分析:算法
本系統中的還款模塊涉及到多種還款方式的算法,而且後期可能須要常常性的調整或增減算法,所以本系統採用策略模式來定義這一系列的算法,把它們一個個封裝起來,而且使它們可相互替換。使得算法可獨立於使用它的客戶而變化。編程
策略模式的結構示意圖:設計模式
圖4-1 策略模式結構圖this
(1) RepaymentModeI:
策略接口,用來約束一系列具體的策略算法。Context使用這個接口來調用具體的策略實現定義的算法。spa
public interface RepaymentModeI { /** * 得到應還利息 *@param annualRate 年利率 *@param loanAount 借款金額 *@param deadline 借款期限 *@param num 還款月數 *@return Double 利息 * */ public Double interest(double annualRate, double loanAount, int deadline, int num); /** * 得到應還本金 *@param annualRate 年利率 *@param loanAount 借款金額 *@param deadline 借款期限 *@param num 還款月數 *@return Double 本金 * */ public Double principal(double annualRate, double loanAount, int deadline, int num); /** * 得到應還本息 *@param annualRate 年利率 *@param loanAount 借款金額 *@param deadline 借款期限 *@return Double 本息 * */ public Double interAndPri(double annualRate, double loanAount, int deadline, int num); /** * 計算利率 * @param annualRate 年利率 * @return 利率 * */ public double rate(double annualRate); }
(2) RepaymentModeBy____:
具體的策略實現,也就是具體的算法實現。目前系統對應有:按天到期還款,按月到期還款(是指每個月還息,到期還本的借款方式),按月分期還款(分期還款採用的是通用的"等額本息還款法"),按季分期付款(採用每個月付息,按季等額還本的計算方式),實現代碼以按月分期還款的計算本金方法爲例:設計
/** * 按月分期還款:分期還款採用的是通用的"等額本息還款法",即借款人每個月以相等的金額償還貸款本息。也是銀行房貸等採用的方法。 * 這裏要注意區分 等額本息還款法和等額本金還款法 * @author sl * */ public Double interAndPri(double annualRate, double loanAount, int deadline, int num) { /** * 等額本息還款公式推導 設貸款總額爲A,銀行月利率爲β,總期數爲m(個月),月還款額設爲X, * 則各個月所欠銀行貸款爲: * 第一個月A(1+β)-X * 第二個月[A(1+β)-X](1+β)-X = A(1+β)^2-X[1+(1+β)] * 第三個月{[A(1+β)-X](1+β)-X}(1+β)-X = A(1+β)^3-X[1+(1+β)+(1+β)^2] * … * 由此可得第n個月後所欠銀行貸款爲: * A(1+β)^n-X[1+(1+β)+(1+β)^2+…+(1+β)^(n-1)] = A(1+β)^n-X[(1+β)^n-1]/β * 因爲還款總期數爲m,也即第m月恰好還完銀行全部貸款,所以有: * A(1+β)^m-X[(1+β)^m-1]/β = 0 * 由此求得: * X = Aβ(1+β)^m/[(1+β)^m-1] * */ Return loanAount*rate(annualRate)*Math.pow((1+rate(annualRate)), deadline)/(Math.pow((1+rate(annualRate)), deadline)-1); }
(3) Context:rest
上下文,負責和具體的策略類交互,一般上下文會持有一個真正的策略實現,上下文還可讓具體的策略類來獲取上下文的數據,甚至讓具體的策略類來回調上下文的方法。code
public class Context { private RepaymentModeI repaymentModeI; private Double annualRate; //年利率 private Double loanAount; //借款金額 private int deadline; //截止期限(按月計算) private int num; //月數 /** * 構造方法,傳入一個具體的策略對象 * @param repaymentMode 具體的策略對象 */ public Context(RepaymentModeI repaymentMode, Double annualRate, Double loanAount,int deadline, int num) { this.repaymentModeI = repaymentMode; this.annualRate = annualRate; this.loanAount = loanAount; this.deadline = deadline; this.num = num; } /** * 上下文對客戶端提供的操做接口,能夠有參數和返回值 */ public Double getInterest() { //得到利息 //一般會轉調具體的策略對象進行算法運算 return repaymentModeI.interest(annualRate, loanAount, deadline, num); } }
策略模式的本質:分離算法,選擇實現。
仔細思考策略模式的結構和實現的功能,會發現,若是沒有上下文,策略模式就回到了最基本的接口和實現了,只要是面向接口編程的,那麼就可以享受到接口的封裝隔離帶來的好處。也就是經過一個統一的策略接口來封裝和隔離具體的策略算法,面向接口編程的話,天然不須要關心具體的策略實現,也能夠經過使用不一樣的實現類來實例化接口,從而實現切換具體的策略。
看起來好像沒有上下文什麼事情,可是若是沒有上下文,那麼就須要客戶端來直接與具體的策略交互,尤爲是當須要提供一些公共功能,或者是相關狀態存儲的時候,會大大增長客戶端使用的難度。所以,引入上下文仍是很必要的,有了上下文,這些工做就由上下文來完成了,客戶端只須要與上下文交互就能夠了,這樣會讓整個設計模式更獨立、更有總體性,也讓客戶端更簡單。
但縱觀整個策略模式實現的功能和設計,它的本質仍是「分離算法,選擇實現」,由於分離並封裝了算法,纔可以很容易的修改和添加算法;也能很容易的動態切換使用不一樣的算法,也就是動態選擇一個算法來實現須要的功能了。對象