设计模式之Template Method模式

来源:互联网 发布:罗德岛大学怎么样知乎 编辑:程序博客网 时间:2024/06/05 10:04

       Template Method模式,模板方法模式。顾名思义,其定义就是在父类中定义处理流程的框架,在子类中实现具体的处理方式。先直接上代码,然后我们再来讨论这种模式。现在的大概需求是这样的。
传入一个char型'A',打印如下结果:


输入“Hello World !”打印出如下结果:


在设计模式中我们用到的例子都是一些很简单的例子,主要阐述的是一种思想,然后在自己的项目中用上,为自己带来便利。


       首先来看看思路:先找出需求对我们行为的要求是啥?打印出一些特殊的字符,或者字符串。可以看出来输入的'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或者需要修改的时候,我们不需要到处找子类去修改,只要修改父类中的这个方法即可。

    

     




1 0
原创粉丝点击