本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7837716.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲行为型设计模式的第一个模式--模板方法模式,先从名字上来看。“模板方法”理解为有一个方法的名字叫“模板方法”,也可以换个理解方法:有一个方法包含了一个模板,这个模板是一个算法。在我们的现实生活中有很多例子可以说明这个模式,就拿吃饺子这个事情来说,要想吃到饺子必须经过三步:第一步是“和面”,第二步是“包馅”,第三步是“煮饺子”,这三步就是一个算法。如果想吃到不同类型的饺子,可以上面的三步中的任意一步进行操作,当然也可以完全定义这三步。下面我们就来看看这个模式的详细介绍吧。
二、模板方法模式介绍
模板方法模式:英文名称--Template Method Pattern;分类--行为型。
2.1、动机(Motivate)
在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
2.2、意图(Intent)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。——《设计模式》GoF
2.3、结构图
2.4、模式的组成
模板方法模式参与者:
1)抽象类角色(AbstractClass):定义一个模板方法(TemplateMethod),在该方法中包含着一个算法的骨架,具体的算法步骤是PrimitiveOperation1方法和PrimitiveOperation2方法,该抽象类的子类将重定义PrimitiveOperation1和PrimitiveOperation2操作。
2)具体类角色(ConcreteClass):实现PrimitiveOperation1方法和PrimitiveOperation2方法以完成算法中与特定子类(Client)相关的内容。
在模板方法模式中,AbstractClass中的TemplateMethod提供了一个标准模板,该模板包含PrimitiveOperation1和PrimitiveOperation2两个方法,这两个方法的内容Client可以根据自己的需要重写。
2.5、模板方法模式的具体实现
理解了模板方法的定义之后,自然实现模板方法也不是什么难事了,下面以生活中吃饺子为例来实现模板方法模式。在现实生活中,做饺子的步骤都大致相同,如果我们针对每种饺子的做法都定义一个类,这样在每个类中都有很多相同的代码。为了解决这个问题,我们一般的思路肯定是把相同的部分抽象出来到抽象类中去定义,具体子类来实现具体的不同部分,这个思路也正是模板方法的实现精髓所在,具体实现代码如下:
class Program { /// <summary> /// 该类型就是抽象类角色--AbstractClass,定义做饺子的算法骨架,这里有三步骤,当然也可以有多个步骤,根据实际需要而定。 /// </summary> public abstract class AbstractClass { //该方法就是模板方法,方法里面包含了做饺子的算法步骤,模板方法可以返回结果,也可以是void类型,视具体情况而定。 public void EatDumplings() { //和面 MakingDough(); //包馅 MakeDumplings(); //煮饺子 BoiledDumplings(); Console.WriteLine("饺子真好吃。"); } //要想吃饺子第一步肯定是“和面”--该方法相当于算法中的某一步 public abstract void MakingDough(); //要想吃饺子第二步是“包饺子”--该方法相当于算法中的某一步 public abstract void MakeDumplings(); //要想吃饺子第三步是“煮饺子”--该方法相当于算法中的某一步 public abstract void BoiledDumplings(); } /// <summary> /// 该类型是具体类角色--ConcreteClass1,我想吃绿色面皮的猪肉大葱馅的饺子。 /// </summary> public sealed class ConcreteClass1 : AbstractClass { //要想吃饺子第一步肯定是“和面”--该方法相当于算法中的某一步 public override void MakingDough() { //我想要面是绿色的,绿色健康嘛,就可以在此步定制了。 Console.WriteLine("在和面的时候加入芹菜汁,和好的面就是绿色的。"); } //要想吃饺子第二部是“包饺子”--该方法相当于算法中的某一步 public override void MakeDumplings() { //我想吃猪肉大葱馅的,在此步就可以定制了。 Console.WriteLine("农家猪肉和农家大葱,制作成馅。"); } //要想吃饺子第三部是“煮饺子”--该方法相当于算法中的某一步 public override void BoiledDumplings() { //我想吃大铁锅煮的饺子,有家的味道,在此步就可以定制了。 Console.WriteLine("用我家的大铁锅和大木材煮饺子。"); } } /// <summary> /// 该类型是具体类角色--ConcreteClass2,我想吃橙色面皮的韭菜鸡蛋馅的饺子。 /// </summary> public sealed class ConcreteClass2 : AbstractClass { //要想吃饺子第一步肯定是“和面”--该方法相当于算法中的某一步 public override void MakingDough() { //我想要面是橙色的,在此步定制就可以了。 Console.WriteLine("在和面的时候加入胡萝卜汁,和好的面就是橙色的。"); } //要想吃饺子第二部是“包饺子”--该方法相当于算法中的某一步 public override void MakeDumplings() { //我想吃韭菜鸡蛋馅的,在此步定制就可以了。 Console.WriteLine("农家鸡蛋和农家韭菜,制作成馅。"); } //要想吃饺子第三部是“煮饺子”--该方法相当于算法中的某一步 public override void BoiledDumplings() { //此处没要求 Console.WriteLine("可以用一般煤气和不粘锅煮就可以。"); } } static void Main(string[] args) { #region 模板方法模式 //现在想吃绿色面皮的猪肉大葱馅的饺子 AbstractClass someone = new ConcreteClass1(); someone.EatDumplings(); Console.WriteLine(); //过了段时间,我开始想吃橙色面皮的韭菜鸡蛋馅的饺子。 someone = new ConcreteClass2(); someone.EatDumplings(); Console.Read(); #endregion } }