概念

模板指一些可以套用的公共内容,例如网页模板是当网站中有许多页面版式色彩相同的情况下,将其定义为网页模板,并定义其中部分可编辑,部分不可编辑,那么在利用网页模板制作其他页面时就会很方便,不易出错。
在设计模式中,模板方法模式中模板和生活中模板概念非常类似,在一个抽象类中定义一个操作中的算法骨架(对应于模板),而将一些步骤延迟到子类中去实现(对应根据自己的情况向模板填充内容)。
在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。此时就可以采用模板方法进行设计。

例如公司的入职流程,进入公司,入职准备、入职报到、办理入职手续、进行入职培训,转正,入职结束进入岗位。这些步骤都很固定,但是不同的公司,流程中每个步骤稍有不同。这些不同的可以在具体实现上进行填充。

特点

优点:
它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
它在父类中提取了公共的部分代码,实现了代码复用。
部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

缺点:
对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
因为引入了一个抽象类,如果具体实现过多的话,需要用户或开发人员需要花更多的时间去理清类之间的关系。

模式结构

根据模板方法模式类图结构,有利于我们理清该模式中类之间的关系,具体类图如下:

模板方法模式中涉及的角色:
抽象模板角色:定义了一个或多个抽象操作,以便让子类实现,这些抽象操作称为基本操作。它由一个模板方法和若干个基本方法构成。
  模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
  基本方法:是整个算法中的一个步骤,包含了抽象方法、具体方法。
具体模板角色:实现父类所定义的一个或多个抽象方法。

应用场景

算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。

实现

以入职流程为例,进行具体的实现。

using System;

namespace 模板模式
{
class EntryProcess
{
static void Main(string[] args)
{
SamsungEntryProcess samsung = new SamsungEntryProcess();
HuaweiEntryProcess huawei = new HuaweiEntryProcess(); samsung.JoiningCompany();
huawei.JoiningCompany(); Console.Read();
}
} // 抽象类,入职流程
public abstract class TemplateEntryProcess
{
// 模板方法,不要把模版方法定义为 Virtual 或 abstract 方法,避免被子类重写,防止更改流程的执行顺序
public void JoiningCompany()
{
this.entryCompany(); // 进入公司
this.preparationForEntry(); // 入职前准备,整理衣帽等
this.registrationForEmployment(); // 入职报到
this.entryProcedures(); // 办理入职手续
this.inductionTraining(); // 入职培训
this.evaluationOfConversion(); // 转正评估
this.entryOver(); // 入职结束,进入岗位
} public abstract void entryCompany(); public void preparationForEntry()
{
Console.WriteLine("做准备,整理衣帽等;");
} public void registrationForEmployment()
{
Console.WriteLine("入职报到;");
}
public void entryProcedures()
{
Console.WriteLine("办理入职手续;");
}
public void inductionTraining()
{
Console.WriteLine("进行入职培训;");
}
public void evaluationOfConversion()
{
Console.WriteLine("完成入职前培训,进行转正评估;");
}
public void entryOver()
{
Console.WriteLine("入职流程完成,进入岗位。");
} } // 具体子类,三星入职
public class SamsungEntryProcess: TemplateEntryProcess
{
public override void entryCompany()
{
Console.WriteLine("进入三星公司");
} } // 具体子类,华为入职
public class HuaweiEntryProcess: TemplateEntryProcess
{
public override void entryCompany()
{
Console.WriteLine("进入华为公司");
}
}
}

执行后结果

进入三星公司
做准备,整理衣帽等;
入职报到;
办理入职手续;
进行入职培训;
完成入职前培训,进行转正评估;
入职流程完成,进入岗位。
进入华为公司
做准备,整理衣帽等;
入职报到;
办理入职手续;
进行入职培训;
完成入职前培训,进行转正评估;
入职流程完成,进入岗位。

最新文章

  1. 第三十一篇:SOUI布局之相对于特定兄弟窗口
  2. 如何预览将要上传的图片-使用H5的FileAPI
  3. 计划任务crontab
  4. 用最简单话概括SSH三框架
  5. Python: sort,sorted,OrderedDict的用法
  6. AC日记——搞笑世界杯 codevs 1060(dp)
  7. uva 10158
  8. Mysql常见问题及优化
  9. 在安装twincat plc时,出现 there are some files marked for deletion on next reboot.please reboot first then
  10. 在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)
  11. dfs算法
  12. SqlServer注意事项总结,高级程序员必背!
  13. MySQL学习基础知识1
  14. ubuntu下adb的使用以及开启黑域
  15. cmd切换代码页,切换字体,cmd不能输入中文
  16. 20175311 2018-2019-2 《Java程序设计》第四周学习总结
  17. C++日常应用-定时器
  18. [转] react-router4 + webpack Code Splitting
  19. Linux 学习手记(2):Linux文件系统的基本结构
  20. ArchLinux新版本(pacstrap安装)及国内较优源推荐

热门文章

  1. Centos-shell-简介
  2. What number should I guess next ?——由《鹰蛋》一题引发的思考
  3. 【LGR-070】洛谷 3 月月赛-官方题解
  4. shell-变量输入内置read命令详解
  5. Elasticsearch(4):映射
  6. C++ 构造函数、拷贝构造函数、赋值运算符
  7. 从面试角度学完 Kafka
  8. 微信小程序 audio组件 默认控件 无法隐藏/一直显示/改了controls=‘false’也没用2019/5/28
  9. day31 Pyhton 总结
  10. Warning: Permanently added the RSA host key for IP address '52.74.223.119' to the list of known hosts.