说说设计模式--模板方法

说说设计模式--模板方法(Template Method)

2016-1-1 by Damon


说说模板方法(Template Method)
一句话总结

父类方法调用抽象方法,方法抽象定义在父类,实际实现处理交给子类,按照流程完成整件事就是“模板方法模式”。

有什么好处

遵照父类定义的前提下,不同的子类可以给父类抽象的模板方法提供不同的实现,提供拓展能力。

简单的小例子

父类:AbstractDisplay

    public abstract class AbstractDisplay {
        // 方法抽象定义在父类
        public abstract void open();
        public abstract void print();
        public abstract void close();

        // 父类方法调用抽象方法
        public final void diplay() {
            open();
            for(int i = 0; i < 5; i++){
                print();
            }
            close();
        }
    }

子类:CharDisplay

    public class CharDisplay extends AbstractDisplay {
        private char ch;
        public CharDisplay(char ch) {
            this.ch = ch;
        }

        public void open() {
            // 具体实现
            System.out.print("<<");
        }

        public void print() {
            // 具体实现
            System.out.print(ch);
        }

        public void close() {
            // 具体实现
            System.out.println(">>");
        }
    }

子类:StringDisplay

    public class StringDisplay extends AbstractDisplay {

        private String string;
        private int width;

        public StringDisplay(String string){
            this.string = string;
            this.width = string.getBytes().length;
        }

        public void open() {
            // 具体实现
            printLine();
        }

        public void print() {
            // 具体实现
            System.out.println("|" + string + "|");
        }

        public void close() {
            // 具体实现
            printLine();
        }

        private void printLine(){
            System.out.print("+");
            for(int i = 0; i < width; i++){
                System.out.print("-");
            }
            System.out.println("+");
        }

    }

测试:Main

    public class Main {

        /**
         * 

main

         * 

         * @author damon          * @date 2016年1月4日          * @param args          */         public static void main(String[] args) {             // TODO Auto-generated method stub             AbstractDisplay d1 = new CharDisplay('H');             d1.diplay();     //      AbstractDisplay d2 = new StringDisplay("Hello");     //      d2.diplay();         }     }
优秀案例分析

前段时间在研究SpringMVC的前端控制器DispatchServlet时看到初始化过程里面有很多类似“模板方法”的变相体现,下面举例分享一下:

HttpServletBean 类

    // 模板方法模式的变相体现
    public final void init() throws ServletException {
        // 忽略其他内容

        // 模板方法调用
        initServletBean();

    }

    /**
     * Subclasses may override this to perform custom initialization.
     * All bean properties of this servlet will have been set before this
     * method is invoked.
     * 

This default implementation is empty.      * @throws ServletException if subclass initialization fails      * 大体翻译:空实现,不处理事情,子类将会提供初始化的实现      * 分析:相比模板方法模式,模板方法模式在父类的模板方法被定义为抽象的,子类必须提供实现,      * 这里采用父类模板方法空实现,子承父类protected的限制,好处是子类可以有选择的实现      */     protected void initServletBean() throws ServletException {     }

HttpServletBean 类 子类 FrameworkServlet 类

    // 模板方法子类实现
    protected final void initServletBean() throws ServletException {
        getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
        if (this.logger.isInfoEnabled()) {
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
        }
        long startTime = System.currentTimeMillis();

        try {
            this.webApplicationContext = initWebApplicationContext();
            initFrameworkServlet();
        }
        catch (ServletException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }
        catch (RuntimeException ex) {
            this.logger.error("Context initialization failed", ex);
            throw ex;
        }

        if (this.logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
                    elapsedTime + " ms");
        }
    }

同样的设计还有,如

FrameworkServlet 类

    protected WebApplicationContext initWebApplicationContext() {
        // 忽略其他内容

        if (!this.refreshEventReceived) {
            // 模板方法调用
            onRefresh(wac);
        }

    }

    /**
     * Template method which can be overridden to add servlet-specific refresh work.
     * Called after successful context refresh.
     * 

This implementation is empty.      * @param context the current WebApplicationContext      * @see #refresh()      */     protected void onRefresh(ApplicationContext context) {         // For subclasses: do nothing by default.     }

FrameworkServlet 类 子类 DispatcherServlet 类

    // 模板方法子类实现
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }