.Net行為型設(shè)計模式之模板方法模式(Template?Method)
一、動機(Motivate)
“模板方法”,就是有一個方法包含了一個模板,這個模板是一個算法。在我們的現(xiàn)實生活中有很多例子可以拿來說明這個模式,就拿吃餃子這個事情來說,要想吃到餃子必須經(jīng)過三步,第一步是“和面”,第二步是“包餡”,第三步是“煮餃子”,這三步就是一個算法,我們要想吃到不同的面和餡的餃子,對這三步中的任意一步就行操作就可以,也可以完全定義這三步
在軟件構(gòu)建過程中,對于某一項任務(wù),它常常有穩(wěn)定的整體操作結(jié)構(gòu),但各個子步驟卻有很多改變的需求,或者由于固有的原因(比如框架與應(yīng)用之間的關(guān)系)而無法和任務(wù)的整體結(jié)構(gòu)同時實現(xiàn)。如何在確定穩(wěn)定操作結(jié)構(gòu)的前提下,來靈活應(yīng)對各個子步驟的變化或者晚期實現(xiàn)需求?
二、意圖(Intent)
定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。 ——《設(shè)計模式》GoF
三、結(jié)構(gòu)圖
四、模式的組成
模板方法模式參與者:
(1)、抽象類角色(AbstractClass):定義一個模板方法(TemplateMethod),在該方法中包含著一個算法的骨架,具體的算法步驟是PrimitiveOperation1方法和PrimitiveOperation2方法,該抽象類的子類將重定義PrimitiveOperation1和PrimitiveOperation2操作。
(2)、具體類角色(ConcreteClass):實現(xiàn)PrimitiveOperation1方法和PrimitiveOperation2方法以完成算法中與特定子類(Client)相關(guān)的內(nèi)容。
在模板方法模式中,AbstractClass中的TemplateMethod提供了一個標準模板,該模板包含PrimitiveOperation1和PrimitiveOperation2兩個方法,這兩個方法的內(nèi)容Client可以根據(jù)自己的需要重寫。
五、模板方法模式的具體實現(xiàn)
下面以生活中吃餃子為例來實現(xiàn)模板方法模式。在現(xiàn)實生活中,做餃子的步驟都大致相同,如果我們針對每種餃子的做法都定義一個類,這樣在每個類中都有很多相同的代碼,為了解決這個問題,我們一般的思路肯定是把相同的部分抽象出來到抽象類中去定義,具體子類來實現(xiàn)具體的不同部分,這個思路也正式模板方法的實現(xiàn)精髓所在,具體實現(xiàn)代碼如下:
static void Main(string[] args) { //現(xiàn)在想吃綠色面的,豬肉大蔥餡的餃子 AbstractClass fan = new ConcreteClass1(); fan.EatDumplings(); Console.WriteLine(); //過了段時間,我開始想吃橙色面的,韭菜雞蛋餡的餃子 fan = new ConcreteClass2(); fan.EatDumplings(); } //該類型就是抽象類角色--AbstractClass,定義做餃子的算法骨架,這里有三步驟,當然也可以有多個步驟,根據(jù)實際需要而定 public abstract class AbstractClass { //該方法就是模板方法,方法里面包含了做餃子的算法步驟,模板方法可以返回結(jié)果,也可以是void類型,視具體情況而定 public void EatDumplings() { MakingDough();//和面 MakeDumplings();//包餡 BoiledDumplings(); //煮餃子 Console.WriteLine("餃子真好吃!"); } public abstract void MakingDough();//要想吃餃子第一步肯定是“和面”---該方法相當于算法中的某一步 public abstract void MakeDumplings();//要想吃餃子第二部是“包餃子”---該方法相當于算法中的某一步 public abstract void BoiledDumplings(); //要想吃餃子第三部是“煮餃子”---該方法相當于算法中的某一步 } //該類型是具體類角色--ConcreteClass,我想吃綠色面皮,豬肉大蔥餡的餃子 public sealed class ConcreteClass1 : AbstractClass { public override void MakingDough() //要想吃餃子第一步肯定是“和面”---該方法相當于算法中的某一步 { Console.WriteLine("在和面的時候加入芹菜汁,和好的面就是綠色的");//我想要面是綠色的,綠色健康嘛,就可以在此步定制了 } public override void MakeDumplings()//要想吃餃子第二部是“包餃子”---該方法相當于算法中的某一步 { Console.WriteLine("農(nóng)家豬肉和農(nóng)家大蔥,制作成餡");//我想吃豬肉大蔥餡的,在此步就可以定制了 } public override void BoiledDumplings()//要想吃餃子第三部是“煮餃子”---該方法相當于算法中的某一步 { Console.WriteLine("用我家的大鐵鍋和大木材煮餃子");//我想吃大鐵鍋煮的餃子,有家的味道,在此步就可以定制了 } } //該類型是具體類角色--ConcreteClass2,我想吃橙色面皮,韭菜雞蛋餡的餃子 public sealed class ConcreteClass2 : AbstractClass { public override void MakingDough()//要想吃餃子第一步肯定是“和面”---該方法相當于算法中的某一步 { Console.WriteLine("在和面的時候加入胡蘿卜汁,和好的面就是橙色的");//我想要面是橙色的,加入胡蘿卜汁就可以。在此步定制就可以了。 } public override void MakeDumplings() //要想吃餃子第二部是“包餃子”---該方法相當于算法中的某一步 { Console.WriteLine("農(nóng)家雞蛋和農(nóng)家韭菜,制作成餡"); //我想吃韭菜雞蛋餡的,在此步就可以定制了 } public override void BoiledDumplings()//要想吃餃子第三部是“煮餃子”---該方法相當于算法中的某一步 { Console.WriteLine("可以用一般煤氣和不粘鍋煮就可以"); //此處沒要求 } }
六、模板方法模式的實現(xiàn)要點:
Template Method模式是一種非常基礎(chǔ)性的設(shè)計模式,在面向?qū)ο笙到y(tǒng)中有著大量的應(yīng)用。它用最簡潔的機制(虛函數(shù)的多態(tài)性)為很多應(yīng)用程序框架提供了靈活的擴展,是代碼復(fù)用方面的基本實現(xiàn)結(jié)構(gòu)。除了可以靈活應(yīng)對子步驟的變化外,“Don't call me, let me call you(不要調(diào)用我,讓我來調(diào)用你)”的反向控制結(jié)構(gòu)是Template Method的典型應(yīng)用。
1、模板方法模式適用情形:
(1)、一次性實現(xiàn)一個算法的不變部分,并將可變的行為留給子類來實現(xiàn)。
(2)、各子類中公共的行為應(yīng)被提取出來并集中到一個公共父類中以避免代碼重復(fù)。
(3)、控制子類擴展。模板方法只允許在特定點進行擴展,而模板部分則是穩(wěn)定的。
2、模板方法模式特點:
(1)、TemplateMethod模式是一種非?;A(chǔ)性的設(shè)計模式,在面向?qū)ο笙到y(tǒng)中大量應(yīng)用。它用最簡潔的機制(基礎(chǔ)、多態(tài))為很多應(yīng)用程序框架提供了靈活的擴展點,是代碼復(fù)用方面的基本實現(xiàn)結(jié)構(gòu)。
(2)、在具體實現(xiàn)方面,被TemplateMethod調(diào)用的虛方法可以具有實現(xiàn),也可以沒有任何實現(xiàn)(抽象方法或虛方法)。但一般推薦將它們設(shè)置為protected方法使得只有子類可以訪問它們。
(3)、模板方法模式通過對子類的擴展增加新的行為,符合“開閉原則”。
七、.NET 中模板模式的實現(xiàn)
這種模式在控件設(shè)計中大量的用到,比如:控件有自己的生命周期,Page對象也有自己的生命周期,Application應(yīng)用對象也有自己的生命周期,這個生命周期里面的每個階段其實就是模板方法里面包含的每個步驟,這些階段步驟會被一個方法包含著,這個方法就是“模板方法”。讓我們再說說控件吧,因為寫好的控件,可能需要被開發(fā)人員自定義,那么在控件里我們已經(jīng)定義好了控件呈現(xiàn)、動作的骨架,但是有些自定義的需求,需要延遲到擴展控件的開發(fā)人員來決定。
當我們在做Windows應(yīng)用程序的時候,就會使用Windows控件,那Windows控件是如何顯示在Windows Form 上的呢,就需要一個OnPaint方法把控件畫出來,這里OnPaint是一個虛方法的子步驟,這就是一個Template Method設(shè)計模式。如果我們不去重寫這個OnPaint方法,它就有一個基本的默認實現(xiàn),畫一個空窗體。這里我們并沒有調(diào)用OnPaint方法,而是Application的Run會進入Windows的消息循環(huán)結(jié)構(gòu),Paint就是一個消息。當我們移動一下窗口都會導致Paint事件的發(fā)生,并導致OnPaint函數(shù)的調(diào)用,這就是一種反向調(diào)用。當然,還有很多其他的子步驟可以提供擴展點,例如OnClose等,很多以O(shè)n開頭的全部都是Template Method模式的虛方法。 這個里面內(nèi)容很復(fù)雜,它并不是用一個Template Method在里面調(diào)用所有的子步驟方法,它實際上是把整體的Template Method方法置于了一個消息循環(huán)的結(jié)構(gòu)里面,我們可以把消息循環(huán)的結(jié)構(gòu)看做模板方法里面的TemplateMethod公有非虛方法。
到此這篇關(guān)于.Net行為型設(shè)計模式之模板方法模式(Template Method)的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ASP.NET Core應(yīng)用啟動Startup類簡介
這篇文章介紹了ASP.NET Core中的應(yīng)用啟動Startup類,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04Linux?CentOS下docker部署Asp.Net?Core(.Net6)
這篇文章介紹了Linux?CentOS下docker部署Asp.Net?Core(.Net6)的方法,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-12-12ASP.NET中Literal與Label控件的區(qū)別
相信學ASP.NET的朋友們都會遇到Literal和Label到底該用那個的問題,Literal和Label到底有什么不同,其實簡單的講就是Literal不會產(chǎn)生HTML代碼,而Label會產(chǎn)生一個span標記,下面為大家詳細講解一下。2016-04-04ASP.NET中 RadioButtonList 單選按鈕組控件的使用方法
本文主要簡單介紹RadioButtonList控件的常見屬性和使用方法,希望對大家有所幫助。2016-04-04連接ACCESS數(shù)據(jù)庫時發(fā)生錯誤提示:找不到可安裝的 ISAM
連接ACCESS數(shù)據(jù)庫時發(fā)生錯誤提示:找不到可安裝的 ISAM 檢查后發(fā)現(xiàn)原來是把Data Source寫成 DataSource了2011-04-04