`
dawuafang
  • 浏览: 1192164 次
文章分类
社区版块
存档分类
最新评论

模板方法模式

 
阅读更多

模板方法模式

标签 : Java与设计模式


模板方法模式: 定义一个操作中的算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变一个算法的结构的前提下重定义该算法的某些特定步骤.

(图片来源: 设计模式:可复用面向对象软件的基础)

  • Tips
    处理某个流程的骨架代码已经具备, 但其中某节点的具体实现暂不确定, 此时可采用模板方法, 将该节点的代码实现转移给子类完成. 即: 处理步骤在父类中定义好, 具体实现延迟到子类中定义.

模式实现

ATM取款机办理业务, 都会经过插卡输密码处理业务取卡 等几个过程, 而且这几个过程一定是顺序执行的, 且除了 处理业务 (如取款、改密、查账) 可能会有所不同之外, 其他的过程完全相同. 因此我们就可以参考模板方法模式插卡输密码取卡 3个过程放到父类中实现, 并定义一个流程骨架, 然后将 处理业务的具体逻辑 放到子类中:

  • AbstractClass 抽象模板:
    • 定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤.
    • 实现一个模板方法,定义一个算法的骨架. 该模板方法不仅调用原语操作,也调用定义在AbstractClass或其他对象中的操作.
/**
 * @author jifang
 * @since 16/8/21 上午10:35.
 */
public abstract class AbstractATMBusiness {

    public void run() {
        System.out.println("-> 插卡");
        System.out.println("-> 输入并校验密码");
        if (checkPassword()) {
            onBusiness();
        }

        System.out.println("-> 取卡");
    }

    // 具体业务处理延迟到子类实现
    protected abstract void onBusiness();

    private boolean checkPassword() {
        // TODO Encode Password, Select DB & Comparison
        return true;
    }
}

AbstractATMBusiness是一个模板方法, 它定义了ATM操作的一个主要步骤并确定他们的先后顺序, 但允许子类改变这些具体步骤以满足各自的需求.

  • ConcreteClass
    实现原语操作以完成算法中与特定子类相关的步骤; 每个AbstractClass都可有任意多个ConcreteClass, 而每个ConcreteClass都可以给出这些抽象方法的不同实现, 从而使得顶级逻辑的功能各不相同:
class CheckOutConcreteATMBusiness extends AbstractATMBusiness {

    @Override
    protected void onBusiness() {
        System.out.println(" ... 取款");
    }
}

class ChangePasswordConcreteATMBusiness extends AbstractATMBusiness {

    @Override
    protected void onBusiness() {
        System.out.println(" ... 修改密码");
    }
}
  • Client
 /**
 * Created by jifang on 15/12/3.
 */
public class Client {

    @Test
    public void client() {
        AbstractATMBusiness changePassword = new ChangePasswordConcreteATMBusiness();
        changePassword.run();

        AbstractATMBusiness checkOut = new CheckOutConcreteATMBusiness();
        checkOut.run();
    }
}

实例

Servlet

HttpServlet定义了service()方法固定下来HTTP请求的整体处理流程,使得开发Servlet只需继承HttpServlet并实现doGet()/doPost()等方法完成业务逻辑处理, 并不需要关心具体的HTTP响应流程:

/**
 * HttpServlet中的service方法
 */
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException{
    String method = req.getMethod();

    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
        // servlet doesn't support if-modified-since, no reason
        // to go through further expensive logic
        doGet(req, resp);
        } else {
        long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
        if (ifModifiedSince < (lastModified / 1000 * 1000)) {
            // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
            maybeSetLastModified(resp, lastModified);
            doGet(req, resp);
        } else {
            resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);   

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);

    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

详见: Servlet - 基础.


统一定时调度

将这个示例放在此处可能有些不大合适, 但它也体现了一些模板方法的思想:


1. 实现

  • ScheduleTaskMonitor
/**
 * @author jifang
 * @since 16/8/23 下午3:35.
 */
public class ScheduleTaskMonitor implements InitializingBean, DisposableBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScheduleTaskMonitor.class);

    private static final int _10S = 10_000;

    private List<ScheduleTask> tasks = new CopyOnWriteArrayList<>();

    private static final Timer timer = new Timer("ScheduleTaskMonitor");

    private void start() {
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                for (ScheduleTask task : tasks) {
                    task.scheduleTask();
                }
            }
        }, 0, _10S);
    }

    public void register(ScheduleTask task) {
        tasks.add(task);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.start();
        LOGGER.info("Start Monitor {}", this.getClass());
    }

    @Override
    public void destroy() throws Exception {
        timer.cancel();
        LOGGER.info("Stop Monitor {}", this.getClass());
    }
}
  • ScheduleTask
public interface ScheduleTask {
    void scheduleTask();
}

2. 使用

只需在Spring的配置文件中引入该Bean:

<bean id="monitor" class="com.template.ScheduleTaskMonitor"/>

需要统一定时的类实现ScheduleTask接口, 并将自己注册到monitor中:

/**
 * @author jifang
 * @since 16/3/16 上午9:59.
 */
@Controller
public class LoginController implements ScheduleTask, InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private ScheduleTaskMonitor monitor;

    @Override
    public void scheduleTask() {
        LOGGER.error("O(∩_∩)O 日志记录~");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        monitor.register(this);
    }
}

即可完成scheduleTask()方法的定时调度.


小结

模板方法模式提供了一个很好的代码复用平台, 他通过把不变行为搬移到父类, 去除子类中重复代码来体现它的优势: 有时我们会遇到由一系列步骤构成的过程需要执行, 该过程从高层次上看是相同的, 但有某些细节的实现可能不同, 此时就可以考虑使用用模板方法了.

  • 适用

    • 一次性实现算法的不变部分, 并将可变的行为留给子类来实现;
    • 各子类中公共的行为应该被提取出来并集中到一个公共父类中避免代码重复, 如: Servletservice()方法.
    • 控制子类扩展, 模板方法只在特定点调用hook操作, 这样就只允许在这些点进行扩展, 如: Junit测试框架.
  • 相关模式

    • Factory Method常被模板方法调用.
    • Strategy: 模板方法使用继承来改变算法的一部分, Strategy使用委托来改变整个算法.

参考 & 扩展
设计模式:可复用面向对象软件的基础
大话设计模式
高淇将设计模式

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

    深入浅出设计模式之模板方法模式

    ### 深入浅出设计模式之模板方法模式 #### 一、模板方法模式概述 设计模式是软件工程中一种非常重要的技术手段,它能够帮助我们解决常见的编程问题,并提高代码的可重用性、可扩展性和可维护性。模板方法模式是一...

    设计模式之模板方法模式

    模板方法模式是面向对象设计模式中的行为模式之一,它在Java等面向对象编程语言中有着广泛的应用。模板方法模式的主要思想是在一个抽象类中定义一个算法的骨架,而将一些步骤延迟到子类中实现。这样,子类可以重写...

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

    ### 设计模式之模板方法模式解析 #### 一、引言 在软件开发过程中,我们经常面临这样的场景:有一些步骤是固定的,而某些步骤则可能因具体实现而异。为了解决这类问题,设计模式中引入了一种叫做“模板方法模式”的...

    设计模式(十一)之模板方法模式.zip

    模板方法模式是面向对象设计中的一种行为设计模式,它在软件工程中扮演着重要的角色,尤其是在需要维护代码的可扩展性和可复用性时。这个模式的核心思想是封装不变的部分,将可变部分抽象出来,让子类进行扩展。通过...

    模板方法模式案例代码

    模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中扮演着重要的角色。这个模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法...

    设计模式-模板方法模式(讲解及其实现代码)

    模板方法模式是一种行为设计模式,它允许在定义行为框架的同时,延迟部分具体步骤到子类中实现。这种模式主要用于在父类中定义算法的骨架,而将一些步骤的实现细节留给子类去完成,从而使得不同的子类可以重用相同的...

    策略模式结合模板方法模式

    策略模式结合模板方法模式的设计思路 策略模式结合模板方法模式是策略模式的一种变形,目的是为了解决策略模式中的一些共性问题。在策略模式中,经常会出现这样一种情况,就是发现这一系列算法的实现上存在公共功能...

    设计模式C++学习之模板方法模式(Template Method)

    模板方法模式(Template Method)是设计模式中行为型模式的一种,它定义了操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。这个模式在C++编程中有着...

    ios-iOS模板方法模式使用心得demo.zip

    在iOS开发中,模板方法模式是一种非常实用的设计模式,它属于行为设计模式,主要用于定义算法的骨架,而将一些步骤延迟到子类中。这种方式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通过...

    设计模式模板方法模式PPT学习教案.pptx

    模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中被广泛使用,用于定义算法的骨架,而将一些步骤延迟到子类中。这样,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定...

    Head First 设计模式 (八) 模板方法模式(Template Method pattern) C++实现

    模板方法模式是设计模式中的一种行为模式,它在软件工程中扮演着重要的角色,尤其是在C++这样的面向对象编程语言中。这种模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的...

    模板方法模式代码示例

    模板方法模式是一种行为设计模式,它在面向对象编程中扮演着重要的角色。这种模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。这样使得子类可以在不改变算法结构的情况下,重新定义该算法的某些特定步骤...

    设计模式--模板方法模式java例子

    模板方法模式是设计模式中行为型模式的一种,它在软件工程中扮演着非常重要的角色,尤其是在Java编程中。模板方法模式定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。它允许子类不改变一个算法的结构即可重...

    模板方法模式例子

    模板方法模式是一种设计模式,属于行为设计模式,它在面向对象设计中扮演着重要的角色。这个模式主要用于定义一个算法的框架,允许子类在不改变整体结构的情况下,对算法的某些步骤进行重写。模板方法模式是基于继承...

    设计模式的模板方法模式的例子

    模板方法模式是设计模式中行为模式的一种,它在软件工程中扮演着重要的角色,尤其是在创建算法框架时。这种模式允许我们在抽象类中定义一个算法的骨架,而将一些步骤延迟到子类中实现,使得子类可以不改变算法的结构...

    模板方法模式demo

    模板方法模式是一种行为设计模式,它允许在定义算法框架的同时,允许子类为一个或多个步骤提供具体的实现。这种模式通常用于代码复用,尤其是在有多种算法相似的情况下,通过抽象出公共部分,让子类专注于具体步骤的...

    7模板方法模式1

    模板方法模式是一种设计模式,属于行为设计模式,它在面向对象编程中扮演着重要的角色。这个模式的主要目的是定义一个操作的框架,也就是算法的主干,同时允许子类在不改变算法整体结构的情况下,对其中特定步骤进行...

Global site tag (gtag.js) - Google Analytics