“四人帮”23种设计模式可分为三大类:创建型,结构型,行为型。每种模式中都有一个最常用的模式,例如,创建型中最常用的是工厂方法模式,结构型模式中最常用的是适配器模式,行为型模式中最常用的是模板方法模式,本节重点讲解模板方法模式。
模板方法模式是最简单的设计模式,起这样的一个名字听起来可能感觉很专业,其实只要大家写过面向对象,就一定熟悉这个模式。说的更简单一点,只要抽象基类中定义了一个受保护的Abastract方法,并提供一个公开的访问接口(供子类访问),然后让子类去重写这个抽象方法,就是模板方法模式最常见的应用。
为什么要用到模板方法模式呢?我们知道,通常写代码的时候,通常一个方法里面会包含几个子方法,但是其中一个方法,在基类中并不知道它具体有什么用途,只能由子类去决定具体要做什么事情,但是在基类中,我们必须按照事情的先后顺序执行(事件1->事件2->事件3->事件4),才能符合正常流程,如下图:
要执行的方法如下:
1 /// <summary> 2 /// schedule template 3 /// </summary> 4 abstract class Schedule 5 { 6 public void Execute() 7 { 8 ExecuteThings1(); 9 ExecuteThings2(); 10 ExecuteThings3(); 11 ExecuteThings4(); 12 } 13 14 private void ExecuteThings1() 15 { 16 //execute the concrete thing for Things1 17 //such as: Print something. 18 } 19 20 private void ExecuteThings3() 21 { 22 //execute the concrete thing for Things3 23 //such as : access the database 24 } 25 26 private void ExecuteThings4() 27 { 28 //execute the concrete thing for Things4 29 //write something to the EventViewer 30 } 31 32 private void ExecuteThings2() 33 { 34 //do nothing 35 } 36 }
可是ExecuteThings2()方法我们不知道要做什么,这时候怎么办呢,直接写成吧,等于写了一个空方法,啥也都执行,并且当子类要继续时也不能根据具体执行什么东东来重写这个方法,这个方法并不能在动态运行时有多种表现,不满足多态的特点。
1 private void ExecuteThings2() 2 { 3 //do nothing 4 }
为了达到子类按需定制,就是大家常说的“钩子”效果,可以首先将方法申明为virtual/abstract,以便子类重写,因为这个方法是一个抽象方法(空方法,什么也不做,等同于C++中的纯虚函数),所以将该方法申明为abstract抽象方法,为了便于子类重写,而不被外界访问,我们使用保护修饰符protected,达到钩子效果,代码如下:
1 /// <summary> 2 /// schedule template 3 /// </summary> 4 abstract class Schedule 5 { 6 public void Execute() 7 { 8 ExecuteThings1(); 9 ExecuteThings2(); 10 ExecuteThings3(); 11 ExecuteThings4(); 12 } 13 14 private void ExecuteThings1() 15 { 16 //execute the concrete thing for Things1 17 //such as: Print something. 18 } 19 20 private void ExecuteThings3() 21 { 22 //execute the concrete thing for Things3 23 //such as : access the database 24 } 25 26 private void ExecuteThings4() 27 { 28 //execute the concrete thing for Things4 29 //write something to the EventViewer 30 } 31 32 private void ExecuteThings2() 33 { 34 //call the hook 35 DoExecuteThings2(); 36 } 37 38 /// <summary> 39 /// hook method, the sub inherited class will implement the details. 40 /// </summary> 41 protected abstract void DoExecuteThings2(); 42 43 }
于是,子类可以按需重写他自己想要执行的事情。
1 class GroupASchedule : Schedule 2 { 3 protected override void DoExecuteThings2() 4 { 5 Console.WriteLine("{0} -> we will execute my plan for GroupA!", this.GetType().Name); 6 } 7 } 8 9 class GroupBSchedule : Schedule 10 { 11 protected override void DoExecuteThings2() 12 { 13 Console.WriteLine("{0} -> we will execute my plan for GroupB!", this.GetType().Name); 14 } 15 }
从而,实现了想做的具体事情2。
示例代码: YearlyArrangement.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Template { abstract class YearlyArrangement { protected virtual void Work() { Console.WriteLine("Most of the time, we are working!"); } /// <summary> /// hook method /// sub-class should override this method /// </summary> protected abstract void MakeEntertainmentEveryYear(); protected virtual void AwardPrize() { Console.WriteLine("At the end of each year, the company holds an award-prize ceremony!"); } protected virtual void AttendAnnualMeeting() { Console.WriteLine("At the end of each year, the company holds an annual meeting!"); } public void MakePlan() { Console.WriteLine("Year: {0}", this.GetType().Name.Replace("Year", string.Empty)); Work(); MakeEntertainmentEveryYear(); AwardPrize(); AttendAnnualMeeting(); Console.WriteLine(); } } }
Year2013.cs:
class Year2013 : YearlyArrangement { protected override void MakeEntertainmentEveryYear() { Console.WriteLine("Travelling to America!"); } }
Year2014.cs:
class Year2014 : YearlyArrangement { protected override void MakeEntertainmentEveryYear() { Console.WriteLine("Travelling to Paris!"); } }
Year2015.cs:
class Year2015 : YearlyArrangement { protected override void MakeEntertainmentEveryYear() { Console.WriteLine("Go to lenovo for learning!"); } }
主函数Program.cs:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Template { class Program { static void Main(string[] args) { Test(); } static void Test() { YearlyArrangement year = new Year2013(); year.MakePlan(); year = new Year2014(); year.MakePlan(); year = new Year2015(); year.MakePlan(); Console.ReadKey(); } } }
运行效果:
源代码下载: https://capps.codeplex.com/releases/view/107754
由于水平有限,难免有描述不够准确之处,欢迎大家指正。