设计模式学习(六):Template Method模板方法模式
创始人
2024-05-12 04:29:48
0

一、什么是Template Method模式

        模板的原意是指带有镂空文字的薄薄的塑料板。只要用笔在模板的镂空处进行临摹,即使是手写也能写出整齐的文字,但是具体写出的文字是什么感觉则依赖于所用的笔。如果使用签字笔来临摹,则可以写出签字似的文字;如果使用铅笔来临摹,则可以写出铅笔字;而如果是用彩色笔临摹,则可以写出彩色的字。但是无论使用什么笔,文字的形状都会与模板上镂空处的形状一致。

        本文中所要学习的Template Method模式是带有模板功能的模式,组成模板的方法被定义在父类中。由于这些方法是抽象方法,所以只查看父类的代码是无法知道这些方法最终会进行何种具体处理的,唯一能知道的就是父类是如何调用这些方法的。

        实现上述这些抽象方法的是子类。在子类中实现了抽象方法也就决定了具体的处理。也就是说,只要在不同的子类中实现不同的具体处理,当父类的模板方法被调用时程序行为也会不同。但是,不论子类中的具体实现如何,处理的流程都会按照父类中所定义的那样进行。

        像这样在父类中定义处理流程的框架,在子类中实现具体处理的模式就称为Template Method模式。

        用一句话来概括:将具体的处理交给子类。

 

二、Template Method示例代码

        这里的示例程序是一段将字符和字符串循环显示5次的简单程序。

 2.1 各类之间的关系

        类的功能:

       类图:

 

2.2  AbstractDisplay类

        通过查看AbstractDisplay类的代码,我们可以知道这3个方法都是抽象方法。也就是说,如果仅仅查看AbstractDisplay类的代码,我们无法知道这3个方法中到底进行了什么样的处理。这是因为open方法、print方法、close方法的实际处理被交给了AbstractDisplay类的子类。

        这里将display用final来修饰,就是表示子类不能重写display方法。

public abstract class AbstractDisplay {public abstract void open();public abstract void print();public abstract void close();public final void display() {open();for (int i = 0; i < 5; i++) {print();}close();}
}

2.3 CharDisplay类

        我们来看看子类之一的charDisplay类。由于CharDisplay类实现了父类AbstractDisplay类中的3个抽象方法 open、print、close,因此它并不是抽象类。这样,当dipslay方法被调用时,比如传入一个H,最终显示出来的会是:<>

public class CharDisplay extends AbstractDisplay{private char ch;public CharDisplay(char ch) {this.ch = ch;}@Overridepublic void open() {System.out.print("<<");}@Overridepublic void print() {System.out.print(ch);}@Overridepublic void close() {System.out.println(">>");}
}

2.4 StringDisplay类

        让我们看看另外一个子类——StringDisplay类。与CharDisplay类一样,它也实现了open、 print、 close方法。
        此时,如果dipslay方法被调用,结果会如何呢?假设我们向charDisplay的构造函数中传递的参数是"Hello,world ,"这个字符串,那么最终结果会像下面这样:

 

public class StringDisplay extends AbstractDisplay{private String string;private int width;public StringDisplay(String string) {this.string = string;this.width = string.getBytes().length;}@Overridepublic void open() {printLine();}@Overridepublic void print() {System.out.println("|" + string + "|");}@Overridepublic void close() {printLine();}private void printLine() {System.out.print("+");for (int i = 0; i < width; i++) {System.out.print("-");}System.out.println("+");}
}

2.5 用于测试的Main方法

        在该类中生成了CharDisplay类和StringDisplay类的实例,并调用了display方法。

public class Main {public static void main(String[] args) {AbstractDisplay d1 = new CharDisplay('H');AbstractDisplay d2 = new StringDisplay("Hello, world.");AbstractDisplay d3 = new StringDisplay("你好,世界。");//虽然都调用的是display方法,但是实际的程序行为//取决于CharDisplay和StringDisplay的具体实现d1.display();d2.display();d3.display();}
}

2.6 运行结果

        虽然都调用的是display方法,但是实际的程序行为取决于CharDisplay和StringDisplay的具体实现 。

三、拓展思路的要点

3.1 可以使逻辑处理通用化

        使用Template Method模式究竟能带来什么好处呢?这里,它的优点是由于在父类的模板方法中编写了算法,因此无需在每个子类中再编写算法。

        例如,我们没使用Template Method模式,而是使用文本编辑器的复制和粘贴功能编写了多个ConcreteClass角色。此时,会出现ConcreteClass1、ConcreteClass2、Concreteclass3等很多相似的类。编写完成后立即发现了Bug还好,但如果是过一段时间才发现在Concreteclass1中有Bug,该怎么办呢?这时,我们就必须将这个Bug 的修改反映到所有的ConcreteClass角色中才行。

        而如果是使用Template Method模式进行编程,当我们在模板方法中发现 Bug时,只需要修改模板方法即可解决问题。

3.2 父类与子类之间的协作

        在Template Method模式中,父类和子类是紧密联系、共同工作的。因此,在子类中实现父类中声明的抽象方法时,必须要理解这些抽象方法被调用的时机。在看不到父类的源代码的情况下,想要编写出子类是非常困难的。

3.3 父类与子类的一致性

        在示例程序中,不论是CharDisplay的实例还是StringDisplay 的实例,都是先保存在AbstractDisplay类型的变量中,然后再来调用display方法的。

        使用父类类型的变量保存子类实例的优点是,即使没有用instanceof等指定子类的种类,程序也能正常工作。

        无论在父类类型的变量中保存哪个子类的实例,程序都可以正常工作,这种原则称为里氏替换原则(The Liskov Substitution Principle,LSP )。当然,LSP并非仅限于Template Method模式,它是通用的继承原则。

四、相关的设计模式

4.1 Factory Method模式

Factory Method模式是将Template Method模式用于生成实例的一个典型例子。

4.2 Strategy模式

        在Template Method模式中,可以使用继承改变程序的行为。这是因为Template Method模式在父类中定义程序行为的框架,在子类中决定具体的处理。

        与此相对的是Strategy模式,它可以使用委托改变程序的行为。与Template Method模式中改变部分程序行为不同的是,Strategy模式用于替换整个算法。

        设计模式学习(四):Strategy策略模式_玉面大蛟龙的博客-CSDN博客

 

五、思考题 

题目

        Java中的接口与抽象类很相似。接口同样也是抽象方法的集合,但是在TemplateMethod模式中,我们却无法使用接口来扮演AbstractClass角色,请问这是为什么呢?

答案

        这是因为TemplateMethod模式中的AbstractClass角色必须实现处理的流程。在抽象类中可以实现一部分方法(例如AbstractDisplay类中的display方法),但是在接口中是无法实现方法的。因此,在TemplateMethod模式中,无法用接口替代抽象类。

相关内容

热门资讯

企业开业主持词 企业开业主持词  主持词是主持人在节目进行过程中用于串联节目的串联词。在当下这个社会中,主持人在各种...
欢送退休职工致辞 欢送退休职工致辞(通用5篇)  在日常学习、工作和生活中,要用到致辞的情况还是蛮多的,致辞要注意人物...
演出节目串词2文 演出节目串词2文(男)尊敬的领导、老师、亲爱的同学们。 (合)大家好。 (女)当鲜红的太阳跃上地平线...
庆祝百岁老人生日的致辞 庆祝百岁老人生日的致辞范文(精选5篇)  在生活、工作和学习中,大家总免不了要接触或使用致辞吧,致辞...
《夏有乔木雅望天堂》的经典台... 《夏有乔木雅望天堂》的经典台词  《夏有乔木雅望天堂》经典台词一  1. 一个等了,却等得太早,一个...
中秋节的主持词 中秋节的主持词  主持人在台上表演的灵魂就表现在主持词中。在当下的中国社会,很多场合都需要主持人活跃...
无间道台词 无间道台词  说好了三年,三年之后又三年,三年之后又三年,都快十年了,老大!  出来跑,迟早要还的。...
六十岁生日宴会致辞 六十岁生日宴会致辞(通用10篇)  在学习、工作或生活中,要用到致辞的情况还是蛮多的,致辞讲求条理性...
终极三国的经典台词 终极三国的经典台词  1.如此如此,这般这般~  2.我姓刘名备,字玄德,是中山靖王的儿子,因为家道...
团代会主持词 团代会主持词  利用在中国拥有几千年文化的诗词能够有效提高主持词的感染力。现今社会在不断向前发展,主...
《剑雨》经典台词盘点 《剑雨》经典台词盘点  1、生未必乐,死未必苦。  2、未来已成现在,现在已成过去,随心而去。  3...
幼儿园园长开园致辞 幼儿园园长开园致辞  在日常学习、工作和生活中,大家都不可避免地会接触到致辞吧,致辞是指在仪式上所讲...
辩论赛主持人主持词开场白 辩论赛主持人主持词开场白  辩论赛怎么能没有我们主持人呢?下面是小编搜集整理的辩论赛主持人主持词开场...
李白凤求凰特殊台词 李白凤求凰特殊台词  在王者荣耀中每个英雄人物都有台词,那么李白凤求凰特殊台词是什么呢?以下是小编整...
学生读书交流会主持词 学生读书交流会主持词  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。在当下的中国社会...
晚会的闭幕词 晚会的闭幕词(精选16篇)  主持词是主持活动的必备稿子,是活跃气氛,引导活动进行的存在,下面是小编...
阿甘正传电影经典台词 阿甘正传电影经典台词大全  《阿甘正传》给我们展现了一个虽然智商只有75,却是忠诚、守信、执着、友善...
致青春经典台词 致青春经典台词  1、青春是有限的,不能在犹豫和观望中度过。  2、很多东西就像气球一样,看上去很美...
追悼会主持词 追悼会主持词  什么是追悼会  追悼会,为悼念死者而召开的会议。有些在死者遗体所在地举行,有些在殡仪...
幼儿园大班新年联欢会主持词   主持人:左XX  开场:  左:亲爱的老师、同学们:  合:大家好!  彭:20XX年马上就要过...