一、模板方法模式定义

模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

从定义中,应该可以看出一部分,为了更好理解,下面就直接上例子:

二、模板方法例子

在敲代码时,累了喝杯咖啡或者喝杯茶,会精神倍增。其实无论咖啡还是茶在冲的时间都是有讲究的。这个在本文不是重点。下面分别描述一下冲泡咖啡和冲泡茶的过程:

两种茶其分别的做法如下代码:

 public class Coffee
{
public void PrepareRecipe()
{
//烧水
BoilWater();
//冲咖啡
BrewCoffeeGrinds();
//倒入茶杯中
PourInCup();
//加入糖和咖啡
AddSugarAndMilk();
}
public void BoilWater()
{
Console.WriteLine("烧水");
} public void BrewCoffeeGrinds()
{
Console.WriteLine("冲咖啡");
} public void PourInCup()
{
Console.WriteLine("倒入杯子中");
} public void AddSugarAndMilk()
{
Console.WriteLine("加糖和牛奶");
}
} public class Tea
{
public void PrepareRecipe()
{
//烧水
BoilWater();
//泡茶
SteepTeaBag();
//倒入茶杯中
PourInCup();
//加入柠檬
AddLemon();
}
public void BoilWater()
{
Console.WriteLine("烧水");
} public void SteepTeaBag()
{
Console.WriteLine("泡茶");
} public void PourInCup()
{
Console.WriteLine("倒入杯子中");
} public void AddLemon()
{
Console.WriteLine("加柠檬");
}
}

在面向对象语言中,是要讲求复用的,现在烧水和带入杯子的方法显然是重复的,这样就不符合对象村的村规——复用。
对比两种做法,都是需要四个步骤,能不能把相同的使用一个基类,不同的部分分别由自己的去实现。其类图如下

如果再细致观察的话,我们的冲咖啡和泡茶以及加入咖啡和牛奶都是属于差不多动作相同的。所以可以继续抽象,抽象后的方法大致如此:

其实得出的也就是我们的模板方法。下面来看看模板方法模式的类图:

三、模板方法类图

从类图可以看到我们把共用的方法放在抽象类中,用于复用。把不确定的方法,放入到具体类中,以便让具体类可以很好的构造自己的方法。除此之外,还有个重点是无论是构造好的方法也好,还是抽象的方法也好,都会被装入到一个TemplateMethod方法中。就像我们平时的做项目也是如此,大致的步骤需要:需求分析——>编码——>测试,这些最基本的过程。但是具体的每一步,可能都是不同的,但是做项目的过程的几个步骤是基本不变的,把步骤抽象成了模板,以后做项目的时间,都按这个步骤去做。这个就是我们的模板方法模式。到这里还是把我们的茶和咖啡沏好。

基类代码:

public abstract class CoffeeinBeverage1
{
public void BoilWater()
{
Console.WriteLine("烧水");
} public void PrepareRecipe()
{
BoilWater();
Brew();
PourInCup();
AddCondiments();
} public void PourInCup()
{
Console.WriteLine("倒入杯子中");
} public abstract void Brew(); public abstract void AddCondiments(); }

咖啡代码:

public class Coffee1 : CoffeeinBeverage1
{
public override void Brew()
{
Console.WriteLine("冲咖啡"); } public override void AddCondiments()
{
Console.WriteLine("加糖和牛奶");
}

茶代码:

public class Tea1 : CoffeeinBeverage1
{
public override void Brew()
{
Console.WriteLine("泡茶");
} public override void AddCondiments()
{
Console.WriteLine("加柠檬");
} }

四、模板方法注意的问题

在上面的茶水和咖啡中,现在是看起来能喝了,但是有个问题就是有些人喝咖啡喜欢不加任何调味料的。那么我们硬是给客人加,肯定是会生气的。为了满足这个要求,设计模式提供的有这个解决方案——使用钩子。具体什么是钩子,我们小的时间的课本上有个猴子捞月亮的图片:

每个猴子不仅会被其他猴子拉住,还会伸出一个手去拉其他猴子。但最后一个手是没有拉其他猴子了,但是还是要伸下去的,以防碰不到月亮。

同样不知道方法能不能用得到,但是有对应的方法,具体的什么时间用得到,什么时间用不到,根据条件来判断。

下面来看看钩子如何在模板方法模式中使用的:

基类代码:

public  void PrepareRecipe()
{
BoilWater();
Brew();
PourInCup();
//有个判断方法来添加调料
if (WantCondiments())
{
AddCondiments();
}
}
/// <summary>
/// 加入一个方法,用来判断是否需要加调料
/// </summary>
/// <returns></returns>
public virtual bool WantCondiments()
{
return true;
}

在子类中,可以通过不同的方式类覆盖WantCondiment()方法。用来表示是否要加调料的标准,在此方法中注意必须加入virtual关键字,以便子类中使用override重写。下面看看咖啡中的方法:

public override bool WantCondiments()
{
return false;
}

下面是测试代码:

class Program
{
static void Main(string[] args)
{
CoffeeinBeverage1 coffeninBeverage = new Coffee1();
coffeninBeverage.PrepareRecipe();
Console.ReadKey();
}
}

输出结果:

发现已经去掉了调料。

五、模板方法模式和策略模式以及工厂方法的对比

在看模板方法的时间,很容易想到工厂方法。因为他们都是让具体的实现放在子类中,但是工厂方法主要是生产出产品,然后去应用产品。模板方法是在于依赖子类中的步骤中的其中几个步骤,具体的步骤已经在基类中写好了。

同样模板方法模式和策略模式都是封装算法。但是策略模式中的每个策略都是单独的一个类。可以随时去更改策略。模板方法模式虽然也是封装了算法,其实主要在于封装步骤,具体的实现是根据依靠各个子类。

除此之外,模板方法模式还涉及到一个好莱坞原则:

不要给我打电话,我会主动和你打电话。

在模板方法模式中扮演好莱坞的角色是抽象类,子类是演员的角色。

一般需要调用子类中的方法都已经在模板中定义好了,需要时,会主动联系各个步骤,最好在子类中不要去调用抽象类中的方法具体方法,以防止子类和父类的调用的凌乱。

六、总结和源码

本文主要先列出了模板方法模式的定义,然后通过例子来帮助理解模式,接着提出钩子在模板方法模式中的使用,最后简单对比了模板方法模式、策略模式以及工厂方法模式。

源码

模板方法模式(Head first 设计模式——7)的更多相关文章

  1. 8.模板方法模式-[Head First 设计模式]

    模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 要点: “模板方法”定义了算法的步骤,把这些步骤的实现延 ...

  2. java模式之-模板方法模式

    模板方法模式是java设计模式常见的模式之一. <JAVA与模式>中写道: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法 ...

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

    今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...

  4. 设计模式(十四)模板方法模式(Template Pattern)

    一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...

  5. C#设计模式-模板方法模式

    提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下 ...

  6. C#设计模式系列:模板方法模式(Template Method)

    你去银行取款的时候,银行会给你一张取款单,这张取款单就是一个模板,它把公共的内容提取到模板中,只留下部分让用户来填写.在软件系统中,将多个类的共有内容提取到一个模板中的思想便是模板方法模式的思想. 模 ...

  7. java设计模式 模板方法模式Template Method

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.毫无疑问,设计模式于己 ...

  8. java设计模式之模板方法模式

    模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差 ...

  9. JAVA 设计模式 模板方法模式

    定义 模板方法模式 (Template Method) 定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成. 模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 模 ...

  10. 深入浅出设计模式——模板方法模式(Template Method Pattern)

    模式动机 模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一.在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中.在模板方法模式 ...

随机推荐

  1. 学习KNN

    转:© 著作权归作者所有 by ido 什么是KNN算法呢?顾名思义,就是K-Nearest neighbors Algorithms的简称.我们可能都知道最近邻算法,它就是KNN算法在k=1时的特例 ...

  2. 域名无法解析 Linux临时或永久修改DNS

    最近给VPS重装了系统,因为服务商不提供DHCP,所以只好手动设置IP和DNS Server.悲催的是系统重装的时候忘记了输入DNS Server,最后导致进去系统后,各种域名无法解析. Linux中 ...

  3. 转载【小程序】: 微信小程序开发---应用与页面的生命周期

    App App() App() 函数用来注册一个小程序.接受一个 object 参数,其指定小程序的生命周期函数等. object参数说明: 属性 类型 描述 触发时机 onLaunch Functi ...

  4. TP3.2之WHERE组合条件处理

    1.条件都是int类型: $User->where('type=1 AND status=1')->select(); 2.条件包含字符串类型: 使用3.1以上版本的话,使用字符串条件的时 ...

  5. iOS10 推送必看 UNNotificationContentExtension

    来源:徐不同(@2016徐小爷) 链接:http://www.jianshu.com/p/45933f5450a4 大伙久等啦~这绝对是最全最详细的 UNNotificationContentExte ...

  6. 【LeetCode】136. Single Number (4 solutions)

    Single Number Given an array of integers, every element appears twice except for one. Find that sing ...

  7. libXext.so.6 libXp.so.6 libXt.so.6 is needed by openmotif21-2.1.30-11.el7.i686

    # rpm -ivh openmotif21--.el7.i686.rpm error: Failed dependencies: libXext.so. -.el7.i686 libXp.so. - ...

  8. 从汇编角度来理解linux下多层函数调用堆栈运行状态

    我们用下面的C代码来研究函数调用的过程.  C++ Code  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16   int bar(int c, int d) {     ...

  9. 三十道linux内核面试题

      1. Linux中主要有哪几种内核锁? Linux的同步机制从2.0到2.6以来不断发展完善.从最初的原子操作,到后来的信号量,从大内核锁到今天的自旋锁.这些同步机制的发展伴随Linux从单处理器 ...

  10. STL应用之set

    之前在解决一道算法题的时候,应用到set,特意对这个stl的容器类做了一些了解.在我的印象中,set就是一个元素不重复的集合,而事实上也正是这样的.无论从MSDN还是任何其它地方,都会告诉我们set的 ...