在地鐵上看《設(shè)計(jì)模式之禪》之模板方法模式。啊除破,還有這種模式,待閱讀完全章后琼腔,這不就是經(jīng)常使用的方法瑰枫。那什么是模板方法模式呢?
一、何為模板方法模式
定義一個(gè)操作中的算法的框架光坝,而將一些步驟延遲到子類中尸诽,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
模板方法在抽象類中定義好基本的流程盯另,各個(gè)子類根據(jù)其具體業(yè)務(wù)場景實(shí)現(xiàn)各個(gè)不同的操作性含。譬如說,我們在日常辦公中經(jīng)常用的審批流程鸳惯。審批的流程整體框架是固定的商蕴,申請人發(fā)起申請,審批人進(jìn)行簽字審批芝发。但是對于不同的審批(考勤審批绪商,離職審批,貸款審批等等)針對于審批人簽字前和簽字后的處理是不同的辅鲸。
離職審批:審批完成之后需要解除人員的相關(guān)系統(tǒng)權(quán)限格郁;請假審批,公司很人性瓢湃,只需要提個(gè)申請單理张,審批完無其他處理;貸款審批:審批之前需要判斷員工是否符合貸款資質(zhì)绵患。
二、模板方法通用類圖
三悟耘、基于模板方法模式設(shè)計(jì)的審批程類圖
ApprovalProcessBase 中Sign
方法為模板方法落蝙,處理整體審批流程,SignBefore
和SignAfter
在考勤審批暂幼,離職審批筏勒,貸款審批有不同的處理。
介紹了這么多旺嬉,我們來看看具體的代碼示例管行。
四、代碼示例
先來看看抽象類ApprovalProcessBase
的實(shí)現(xiàn)
public abstract class ApprovalProcessBase
{
public virtual bool SignBefore(Approval model)
{
return true;
}
public virtual bool SignAfter(Approval model)
{
return true;
}
public bool Sign(Approval model)
{
var signBefore = this.SignBefore(model);
var sign = SignHandle(model);
//進(jìn)行簽字后操作
return this.SignAfter(model);
}
/// <summary>
/// 進(jìn)行簽字
/// </summary>
/// <param name=""></param>
/// <returns></returns>
private bool SignHandle(Approval model)
{
//校驗(yàn)簽字人密碼等等
return true;
}
}
各個(gè)實(shí)現(xiàn)類的實(shí)現(xiàn)邪媳。
公司管理很人性捐顷,請假只需要提交申請單,審批前和審批后無需任何處理雨效。默認(rèn)使用抽象類中ApprovalProcessBase
定義的處理方式
public class AttendanceProcess: ApprovalProcessBase
{
}
離職審批則不同了迅涮,審批后需要解除員工權(quán)限
public class LeaveProcess: ApprovalProcessBase
{
public override bool SignAfter(Approval model)
{
//解除員工權(quán)限
return RemoveAuth();
}
}
假若公司規(guī)定,在公司工作超過3年徽龟,才可以向公司低息貸款叮姑,那么貸款申請審批,需要在審批前据悔,驗(yàn)證員工的貸款資質(zhì)
public class LoanProcess: ApprovalProcessBase
{
public override bool SignBefotr(Approval model)
{
//驗(yàn)證員工貸款資質(zhì)
return ValidifEmployeeCertificate();
}
}
五传透、模板方法模式的擴(kuò)展
在通常情況下耘沼,簽字前簽字后處理的結(jié)果影響審批流程的處理。貸款審批朱盐,簽字前進(jìn)行資質(zhì)驗(yàn)證耕拷,若員工不滿足貸款條件,則不允許貸款托享,不能通過簽字骚烧,審批不通過。也就是抽象類ApprovalProcessBase
中方法Sign
依賴于SignBefore
SignAfter
的執(zhí)行結(jié)果闰围,那該如何設(shè)計(jì)呢赃绊?可以使用鉤子方法(Hook Method)。
鉤子方法:抽象類中定義的一個(gè)空實(shí)現(xiàn)的方法羡榴,子類可以實(shí)現(xiàn)它碧查,從而改變父類模板方法的執(zhí)行邏輯。在
C#
定義為虛方法校仑,關(guān)鍵詞virtual
,Java
中為abstract
忠售。
看到這里,你也許會(huì)說那SignBefore
和SIgnAfter
不就是鉤子方法嗎迄沫?是的稻扬,他們就是鉤子方法,通過各自的條件改變羊瘩,影響模板方法的執(zhí)行泰佳。我們就可以將Sign
方法做以下修改:
public bool Sign(Approval model)
{
var signBefore = this.SignBefore(model);
if (!signBefore)
{
SendEmpolyeeNotice();//通知員工失敗原因
return false;
}
var sign = SignHandle(model);
//進(jìn)行簽字后操作
var signAfter= this.SignAfter(model);
if (signAfter)
{
SendEmployeeNoteceOfSuccess();//通知用戶成功
return true;
}
CallBackTheOperation();//失敗將前面操作回滾
return false;
}
調(diào)用類
public class HandleApprove
{
public bool Approve(string type)
{
switch (type)
{
case "Attendance":
return new AttendanceProcess().Sign();
case "Leave":
return new LeaveProcess().Sign();
case "Loan":
return new LoanProcess().Sign();
default:
return false;
}
}
}
六、模板方法模式優(yōu)點(diǎn)
通過這個(gè)例子我們可以看到模板方法有以下幾個(gè)優(yōu)點(diǎn):
- 封裝尘吗,可擴(kuò)展:將不變的地方封裝到父類實(shí)現(xiàn)逝她,將可變的部分通過繼承在子類繼續(xù)擴(kuò)展;
- 提取公共代碼睬捶,便于維護(hù)黔宛。
七、模板方法模式適用場景
- 代碼重構(gòu)時(shí):將相同的代碼抽取到父類擒贸,然后通過鉤子函數(shù)臀晃,約束其行為;
- 多個(gè)子類有公有的方法酗宋,且邏輯基本相同积仗;
- 重要,復(fù)雜的算法蜕猫,把核心算法設(shè)計(jì)為模板方法寂曹,其他相關(guān)細(xì)節(jié)功能由各個(gè)子類實(shí)現(xiàn)。
審批流程設(shè)計(jì)好了。現(xiàn)在有離職審批LeaveProcess
隆圆,考勤審批AttendanceProcess
漱挚,貸款審批LoanProcess
,日后會(huì)增加其他的如報(bào)銷審批渺氧,轉(zhuǎn)正審批等等旨涝,那么每增加一個(gè)審批類別,就需要修改HandleApprove
侣背,擴(kuò)展性不佳白华。希望審批種類增加,但是審批處理類HandleApprove
不需修改贩耐,這該如何設(shè)計(jì)呢弧腥?
欲解決此問題,請看下一篇《設(shè)計(jì)模式之工廠方法模式》潮太。