C#设计模式之十三模板方法模式(Template Method Pattern)【行为型】

原文:C#设计模式之十三模板方法模式(Template Method Pattern)【行为型】

一、引言

“结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式。现在我们开始讲【行为型】设计模式的第一个模式,该模式是【模板方法】,英文名称是: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、模板方法模式的具体实现

理解了模板方法的定义之后,自然实现模板方法也不是什么难事了,下面以生活中吃饺子为例来实现模板方法模式。在现实生活中,做饺子的步骤都大致相同,如果我们针对每种饺子的做法都定义一个类,这样在每个类中都有很多相同的代码,为了解决这个问题,我们一般的思路肯定是把相同的部分抽象出来到抽象类中去定义,具体子类来实现具体的不同部分,这个思路也正式模板方法的实现精髓所在,具体实现代码如下:

  1 namespace 模板方法模式的实现
  2 {
  3     /// <summary>
  4     /// 好吃不如饺子,舒服不如倒着,我最喜欢吃我爸爸包的饺子,今天就拿吃饺子这件事来看看模板方法的实现吧
  5     /// </summary>
  6     class Client
  7     {
  8         static void Main(string[] args)
  9         {
 10             //现在想吃绿色面的,猪肉大葱馅的饺子
 11             AbstractClass fan = new ConcreteClass();
 12             fan.EatDumplings();
 13
 14             Console.WriteLine();
 15             //过了段时间,我开始想吃橙色面的,韭菜鸡蛋馅的饺子
 16             fan = new ConcreteClass2();
 17             fan.EatDumplings();
 18
 19
 20             Console.Read();
 21         }
 22     }
 23
 24
 25     //该类型就是抽象类角色--AbstractClass,定义做饺子的算法骨架,这里有三步骤,当然也可以有多个步骤,根据实际需要而定
 26     public abstract class AbstractClass
 27     {
 28         //该方法就是模板方法,方法里面包含了做饺子的算法步骤,模板方法可以返回结果,也可以是void类型,视具体情况而定
 29         public void EatDumplings()
 30         {
 31             //和面
 32             MakingDough();
 33             //包馅
 34             MakeDumplings();
 35             //煮饺子
 36             BoiledDumplings();
 37
 38             Console.WriteLine("饺子真好吃!");
 39         }
 40
 41         //要想吃饺子第一步肯定是“和面”---该方法相当于算法中的某一步
 42         public abstract void MakingDough();
 43
 44         //要想吃饺子第二部是“包饺子”---该方法相当于算法中的某一步
 45         public abstract void MakeDumplings();
 46
 47         //要想吃饺子第三部是“煮饺子”---该方法相当于算法中的某一步
 48         public abstract void BoiledDumplings();
 49     }
 50
 51     //该类型是具体类角色--ConcreteClass,我想吃绿色面皮,猪肉大葱馅的饺子
 52     public sealed class ConcreteClass : AbstractClass
 53     {
 54         //要想吃饺子第一步肯定是“和面”---该方法相当于算法中的某一步
 55         public override void MakingDough()
 56         {
 57             //我想要面是绿色的,绿色健康嘛,就可以在此步定制了
 58             Console.WriteLine("在和面的时候加入芹菜汁,和好的面就是绿色的");
 59         }
 60
 61         //要想吃饺子第二部是“包饺子”---该方法相当于算法中的某一步
 62         public override void MakeDumplings()
 63         {
 64             //我想吃猪肉大葱馅的,在此步就可以定制了
 65             Console.WriteLine("农家猪肉和农家大葱,制作成馅");
 66         }
 67
 68         //要想吃饺子第三部是“煮饺子”---该方法相当于算法中的某一步
 69         public override void BoiledDumplings()
 70         {
 71             //我想吃大铁锅煮的饺子,有家的味道,在此步就可以定制了
 72             Console.WriteLine("用我家的大铁锅和大木材煮饺子");
 73         }
 74     }
 75
 76     //该类型是具体类角色--ConcreteClass2,我想吃橙色面皮,韭菜鸡蛋馅的饺子
 77     public sealed class ConcreteClass2 : AbstractClass
 78     {
 79         //要想吃饺子第一步肯定是“和面”---该方法相当于算法中的某一步
 80         public override void MakingDough()
 81         {
 82             //我想要面是橙色的,加入胡萝卜汁就可以。在此步定制就可以了。
 83             Console.WriteLine("在和面的时候加入胡萝卜汁,和好的面就是橙色的");
 84         }
 85
 86         //要想吃饺子第二部是“包饺子”---该方法相当于算法中的某一步
 87         public override void MakeDumplings()
 88         {
 89             //我想吃韭菜鸡蛋馅的,在此步就可以定制了
 90             Console.WriteLine("农家鸡蛋和农家韭菜,制作成馅");
 91         }
 92
 93         //要想吃饺子第三部是“煮饺子”---该方法相当于算法中的某一步
 94         public override void BoiledDumplings()
 95         {
 96             //此处没要求
 97             Console.WriteLine("可以用一般煤气和不粘锅煮就可以");
 98         }
 99     }
100 }

这个模式很简单,备注也很详细,看备注应该差不多了,还有一点就是,模板方法里面的算法步骤,可以有默认实现,也可以没有实现,在C#里面可以是抽象方法,当然模板方法也可以有有返回值,也可以没有返回值。

三、模板方法模式的实现要点:
    
    Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展,是代码复用方面的基本实现结构。除了可以灵活应对子步骤的变化外,“Don‘t call me, let me call you(不要调用我,让我来调用你)”的反向控制结构是Template Method的典型应用。

模板方法模式适用情形:

  (1)、 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。

  (2)、 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

  (3)、 控制子类扩展。模板方法只允许在特定点进行扩展,而模板部分则是稳定的。

  模板方法模式特点:

  (1)、 TemplateMethod模式是一种非常基础性的设计模式,在面向对象系统中大量应用。它用最简洁的机制(基础、多态)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。

  (2)、 在具体实现方面,被TemplateMethod调用的虚方法可以具有实现,也可以没有任何实现(抽象方法或虚方法)。但一般推荐将它们设置为protected方法使得只有子类可以访问它们。

  (3)、 模板方法模式通过对子类的扩展增加新的行为,符合“开闭原则”。

四、.NET 中模板模式的实现

这种模式在控件设计中大量的用到,比如:控件有自己的生命周期,Page对象也有自己的生命周期,Application应用对象也有自己的生命周期,这个生命周期里面的每个阶段其实就是模板方法里面包含的每个步骤,这些阶段步骤会被一个方法包含着,这个方法就是“模板方法”。让我们再说说控件吧,因为写好的控件,可能需要被开发人员自定义,那么在控件里我们已经定义好了控件呈现、动作的骨架,但是有些自定义的需求,需要延迟到扩展控件的开发人员来决定。     

当我们在做Windows应用程序的时候,就会使用Windows控件,那Windows控件是如何显示在Windows Form 上的呢,就需要一个OnPaint方法把控件画出来,这里OnPaint是一个虚方法的子步骤,这就是一个Template Method设计模式。如果我们不去重写这个OnPaint方法,它就有一个基本的默认实现,画一个空窗体。这里我们并没有调用OnPaint方法,而是Application的Run会进入Windows的消息循环结构,Paint就是一个消息。当我们移动一下窗口都会导致Paint事件的发生,并导致OnPaint函数的调用,这就是一种反向调用。当然,还有很多其他的子步骤可以提供扩展点,例如OnClose等,很多以On开头的全部都是Template Method模式的虚方法。 这个里面内容很复杂,它并不是用一个Template Method在里面调用所有的子步骤方法,它实际上是把整体的Template Method方法置于了一个消息循环的结构里面,我们可以把消息循环的结构看做模板方法里面的TemplateMethod公有非虚方法。

五、总结

今天就到此为止吧,该去做饭了,我们的“模板方法”模式也就写完了。曾经有一个人,当然也是写程序的人了说,如果一个人使用面向对象的语言写程序,但是没有用过“模板方法”模式,敢肯定这个人写的程序也绝不是面向对象的,只不过是使用了面向对象的语言而已。虽然有点严厉和刻薄,但是不无道理,这个模式很简单,可能大家在有意或者无意的情况下已经使用过这个模式了,也许只是不知道它的名称而已。

原文地址:https://www.cnblogs.com/lonelyxmas/p/8342797.html

时间: 2024-10-12 05:13:43

C#设计模式之十三模板方法模式(Template Method Pattern)【行为型】的相关文章

设计模式 - 模板方法模式(template method pattern) JFrame 详解

模板方法模式(template method pattern) JFrame 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式(template method pattern), Java的JFrame使用模板方法模式, paint()是可以覆盖的方法,

设计模式 - 模板方法模式(template method pattern) Applet 详解

模板方法模式(template method pattern) Applet 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式(template method pattern), applet就是一个能够在网页上面执行的小程序, applet有很多钩子(

设计模式 - 模板方法模式(template method pattern) 排序(sort) 详解

模板方法模式(template method pattern) 排序(sort) 详解 本文地址: http://blog.csdn.net/caroline_wendy 参考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式的一个主要的应用是排序(sort)算法. 对象的排列方式并不是完全相同, 所以需要排序(sort)算法compareTo()

设计模式 - 模板方法模式(template method pattern) 详解

模板方法模式(template method pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy 模板方法模式(template method pattern): 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤. 模板方法可以进行挂钩(hook), 钩子(hook)是一种被声明在抽象类中的方法, 但只有空的或者默认的实现. 钩子的存在, 可以让子类有能力

设计模式 - 模板方法模式(template method pattern) JFrame 具体解释

模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式(template method pattern), Java的JFrame使用模板方法模式, paint()是能够覆盖的方

设计模式 - 模板方法模式(template method pattern) Applet 具体解释

模板方法模式(template method pattern) Applet 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式(template method pattern), applet就是一个可以在网页上面运行的小程序, applet有非常多

设计模式 - 模板方法模式(template method pattern) 排序(sort) 具体解释

模板方法模式(template method pattern) 排序(sort) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(template method pattern): http://blog.csdn.net/caroline_wendy/article/details/32159455 模板方法模式的一个基本的应用是排序(sort)算法. 对象的排列方式并非全然同样, 所以须要排序(sort)算法compareTo(

设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习&quot;模板方法模式&quot;(Template Method Pattern)

今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知,醋溜土豆丝,好吃不上火.清炒苦瓜这道菜好啊,更是夏天必备之良菜,其功效在此就不做过多赘述了.言归正传,上篇博客我们从“小弟”中学习了“外观模式”,我们也把“外观模式”戏称为“小弟模式”.今天我们要从醋溜土豆丝和清炒苦瓜的制作过程中来学习一下我们今天博客的主题“模板方法模式”(Template Me

设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1:银行业务办理流程在银行办理业务时,一般都包含几个基本固定步骤:取号排队->办理具体业务->对银行工作人员进行评分.取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能取款.存款或者转账. 2.问题 如何保证架构逻辑的正常执行,而不被子类破坏 ? 3.解决

设计模式(行为型)之模板方法模式(Template Method Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(行为型)之命令模式(Command Pattern)>http://blog.csdn.net/yanbober/article/details/45500113 概述 模板方法模式是一种基于继承的代码复用,它是一种类行为型模式:是结构最简单的行为型设计模式,在其结构