设计模式学习(六):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模式中,无法用接口替代抽象类。

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...