Template Method模式,模板方法模式。顾名思义,其定义就是在父类中定义处理流程的框架,在子类中实现具体的处理方式。先直接上代码,然后我们再来讨论这种模式。现在的大概需求是这样的。
传入一个char型'A',打印如下结果:
在设计模式中我们用到的例子都是一些很简单的例子,主要阐述的是一种思想,然后在自己的项目中用上,为自己带来便利。
首先来看看思路:先找出需求对我们行为的要求是啥?打印出一些特殊的字符,或者字符串。可以看出来输入的'A'和'Hello World !'都被循环打印了5遍,在打印之前和之后都有别的处理,但是字符和字符串打印之前和打印之后的处理却明显不一样,并且字符串打印的时候,很明显增加了这个玩意儿'|'。那大体的流程就有了,在打印之前调用一个方法open,然后写一个for循环去打印字符和字符串,最后在调用一个close方法作为结束的处理。对应成代码就是下面酱紫的。
先定义一个基类AbstractDisplay,在该方法中共第一四个方法open,close,print,display。首先open,close,print这三个方法是抽象方法,并未去实现,只是规定了行为。具体怎么做交给子类,自由发挥。display方法则是将子类都要做的流程直接写出来以便子类都能用,不用在每一个子类中都去写重复的代码。
/** * Created by PICO-USER Dragon on 2017/3/9. */ public abstract class AbstractDisplay { protected abstract void open(); protected abstract void close(); protected abstract void print(); public final void display() { open(); for (int i = 0; i < 5; i++) { print(); } close(); } }接着需要先定义一个CharDisplay类继承于AbstractDisplay类,具体实现父类的抽象方法。做自己想要做的动作。
/** * Created by PICO-USER on 2017/3/9. */ public class CharDisplay extends AbstractDisplay { private char charA; public CharDisplay(char charA) { this.charA = charA; } @Override public void open() { System.out.print("<< "); } @Override public void close() { System.out.print(" >>\n"); } @Override public void print() { System.out.print(charA); } }还有一个StringDisplay子类,跟CharDisplay类大同小异。
/** * Created by PICO-USER on 2017/3/9. */ public class StringDisplay extends AbstractDisplay { private String string; public StringDisplay(String string) { this.string = string; } @Override public void open() { System.out.print("+"); for (int i = 0; i < 15; i++) { System.out.print("-"); } System.out.print("+\n"); } @Override public void close() { open(); } @Override public void print() { System.out.print("| " + string + " |\n"); } }最后就是主方法调用了。
public class TemplateMethod { public static void main(String[] args0) { AbstractDisplay charDisplay = new CharDisplay('A'); AbstractDisplay stringDisplay = new StringDisplay("Hello World !"); charDisplay.display(); stringDisplay.display(); } }好了,到这儿代码就完了。开篇已经很清楚的说明了该设计模式的思想,现在我们来说一些细节的东西。
请注意看display这个方法,这个方法是被final修饰的,为啥用他修饰呢?在里氏替换原则中第一条就是子类可以实现父类的抽象方法,但是不能修改父类的抽象方法,这儿display虽然不是抽象方法,但是他却是子类中公用的一个方法,约定了这种行为,子类就不能对这种行为进行修改,所以用final修饰,不让子类重写该方法。
public final void display()
再看TemplateMethod类中调用display方法的代码,这儿是用的父类AbstractDisplay来调用,而不是StringDisplay,为什么这么做呢?这是为了保证子类和父类的一致性。即是没有instanceof等指定子类的种类,程序也能正常使用。这就是里氏替换原则中说到的无论在父类型中保存那个子类的实例,程序都能正常的工作。
AbstractDisplay stringDisplay = new StringDisplay("Hello World !"); stringDisplay.display();
现在有一个问题:我们能不能用接口去代替AbstractDisplay?答案是:不可以,因为我们这种模式的侧重点在于由父类决定处理流程,这处理流程display方法必须要在父类中去实现,但是接口是不能去实现方法的。
好了到这儿,我们这篇文章就算是完了。那我们Template Method模式的具体有电体现在哪儿呢?
那就是我们不需要在每一个子类中去写display方法的处理流程,这样在以后这个功能出现bug或者需要修改的时候,我们不需要到处找子类去修改,只要修改父类中的这个方法即可。