本笔记摘抄自: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
}
}

运行结果如下:

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

抽象方法,当然模板方法也可以有返回值,也可以没有返回值。

三、模板方法模式的实现要点

Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提

供了灵活的扩展,是代码复用方面的基本实现结构。除了可以灵活应对子步骤的变化外,“Don't call me, let me call you(不要调用我,让我来调用你)”的反

向控制结构是Template Method的典型应用。

3.1、模板方法模式适用情形

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

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

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

3.2、模板方法模式特点

1)Template Method模式是一种非常基础性的设计模式,在面向对象系统中大量应用。它用最简洁的机制(基础、多态)为很多应用程序框架提供了灵活

的扩展点,是代码复用方面的基本实现结构。

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公有非虚方法。

五、总结

曾经有一个写程序的人说,如果一个人使用面向对象的语言写程序,但是没有用过“模板方法”模式,敢肯定这个人写的程序也绝不是面向对象的,只不过是

使用了面向对象的语言而已。虽然有点严厉和刻薄,但是不无道理。这个模式很简单,可能大家在有意或者无意的情况下已经使用过这个模式了,也许只是不

知道它的名称而已。

C#设计模式学习笔记:(13)模板方法模式的更多相关文章

  1. 设计模式学习笔记--备忘录(Mamento)模式

    写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方式,这就是软件模式:每个模式描写叙述了一个在我们程序设计中常常发生的问题,以及该问题的解决方式:当我们碰到模 ...

  2. javascript设计模式(张容铭)学习笔记 - 照猫画虎-模板方法模式

    模板方法模式(Template Method):父类中定义一组操作算法骨架,而降一些实现步骤延迟到子类中,使得子类可以不改变父类的算法结构的同时可重新定义算法中某些实现步骤. 项目经理体验了各个页面的 ...

  3. 设计模式学习笔记-Adapter模式

    Adapter模式,就是适配器模式,使两个原本没有关联的类结合一起使用. 平时我们会经常碰到这样的情况,有了两个现成的类,它们之间没有什么联系,但是我们现在既想用其中一个类的方法,同时也想用另外一个类 ...

  4. Java-马士兵设计模式学习笔记-装饰者模式

    Java装饰者模式简介 一.假设有一个Worker接口,它有一个doSomething方法,Plumber和Carpenter都实现了Worker接口,代码及关系如下: 1.Worker.java p ...

  5. 研磨设计模式学习笔记2--外观模式Facade

    需求:客户端需要按照需求,执行一个操作,操作包括一个系统中的3个模块(根据配置选择是否全部执行). 外观模式优点: 客户端无需知道系统内部实现,,只需要写好配置文件,控制那些模块执行,简单易用. 外观 ...

  6. 设计模式学习笔记 1.factory 模式

    Factory 模式 用户不关心工厂的具体类型,只知道这是一个工厂就行. 通过工厂的实现推迟到子类里面去来确定工厂的具体类型. 工厂的具体类型来确定生产的具体产品. 同时用户不关心这是一个什么样子的产 ...

  7. 设计模式学习笔记——Composite 组合模式

    用于描述无限层级的复杂对象,类似于描述资源管理器,抽象出每一个层级的共同特点(文件夹和文件,展开事件) 以前描述一个对象,是将整个对象的全部数据都描述清楚,而组合模式通过在对象中定义自己,描述自己的下 ...

  8. 设计模式学习笔记——Bridge 桥接模式

    先说一下我以前对桥接模式的理解:当每个类中都使用到了同样的属性或方法时,应该将他们单独抽象出来,变成这些类的属性和方法(避免重复造轮子),当时的感觉是和三层模型中的model有点单相似,也就是让mod ...

  9. 设计模式学习笔记——Visitor 访问者模式

    1.定义IVisitor接口,确定变化所涉及的方法 2.封装变化类.实现IVisitor接口 3.在实体类的变化方法中传入IVisitor接口,由接口确定使用哪一种变化来实现(封装变化) 4.在使用时 ...

  10. Java-马士兵设计模式学习笔记-责任链模式-FilterChain功能

    一.目标 增加filterchain功能 二.代码 1.Filter.java public interface Filter { public String doFilter(String str) ...

随机推荐

  1. pikachu漏洞练习之sql注入

    这里因为实验的时候只记录了一部分所以就展示一部分 1.1.1数字型注入 (1)看到界面发现是查询id功能,没有在url里看到有传参所以应该是post方法提交数据. (2)进行sql注入之前我们最好是先 ...

  2. IntelliJ IDEA编辑文件的时候CPU飙高问题的解决

    原文地址:https://www.javatang.com/archives/2018/04/26/25582403.html 上篇文章中说明了解决IntelliJ IDEA中文输入法无提示的问题,最 ...

  3. 深入Nodejs模块fs - 文件系统操作

    node 的fs文档密密麻麻的 api 非常多,毕竟全面支持对文件系统的操作.文档组织的很好,操作基本分为文件操作.目录操作.文件信息.流这个大方面,编程方式也支持同步.异步和 Promise. 本文 ...

  4. Excel Application操作指南

    概述 Application对象是Microsoft Office Excel 2007对象模型中最高级别的对象,表示Excel程序自身.Application对象提供正在运行的程序的信息.应用于程序 ...

  5. 矩阵matrix变换的用法(css3属性transform: matrix)

    参数 2D矩阵的表示 matrix(a,b,c,d,e,f),其中6个参数在矩阵的分布: -- -- | a c e | | b d f | | 0 0 1 | -- -- 在CSS3中矩阵的原始值是 ...

  6. php--->cookie和session

    cookie和session cookie和session理解 HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有 ...

  7. PKU-3580 SuperMemo(Splay模板题)

    SuperMemo 题目链接 Your friend, Jackson is invited to a TV show called SuperMemo in which the participan ...

  8. Docker底层架构之简介

    简介 Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces) 控制组(Control groups) Union 文件系统(Union file systems) 容器格式 ...

  9. django用户认证的session的应用

    from django.shortcuts import render,redirect def login(request): if request.method=='GET': return re ...

  10. 互联网那些事 | MQ数据丢失

    本系列故事的所有案例和解决方案只是笔者以前在互联网工作期间的一些事例,仅供大家参考,实际操作应该根据业务和项目情况设计,欢迎大家留言提出宝贵的意见 背景 小王和小明分别维护分布式系统中A.b两个服务, ...