标签:
标签 : Java与设计模式
模板方法模式: 定义一个操作中的算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变一个算法的结构的前提下重定义该算法的某些特定步骤.
(图片来源: 设计模式:可复用面向对象软件的基础)
到ATM取款机办理业务, 都会经过插卡、输密码、处理业务、取卡 等几个过程, 而且这几个过程一定是顺序执行的, 且除了 处理业务 (如取款、改密、查账) 可能会有所不同之外, 其他的过程完全相同. 因此我们就可以参考模板方法模式把插卡、输密码、取卡 3个过程放到父类中实现, 并定义一个流程骨架, 然后将 处理业务的具体逻辑 放到子类中:
/**
* @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操作的一个主要步骤并确定他们的先后顺序, 但允许子类改变这些具体步骤以满足各自的需求.
class CheckOutConcreteATMBusiness extends AbstractATMBusiness {
@Override
protected void onBusiness() {
System.out.println(" ... 取款");
}
}
class ChangePasswordConcreteATMBusiness extends AbstractATMBusiness {
@Override
protected void onBusiness() {
System.out.println(" ... 修改密码");
}
}
/**
* 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();
}
}
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 - 基础.
将这个示例放在此处可能有些不大合适, 但它也体现了一些模板方法的思想:
/**
* @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());
}
}
public interface ScheduleTask {
void scheduleTask();
}
只需在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()
方法的定时调度.
模板方法模式提供了一个很好的代码复用平台, 他通过把不变行为搬移到父类, 去除子类中重复代码来体现它的优势: 有时我们会遇到由一系列步骤构成的过程需要执行, 该过程从高层次上看是相同的, 但有某些细节的实现可能不同, 此时就可以考虑使用用模板方法了.
适用
service()
方法.相关模式
标签:
原文地址:http://blog.csdn.net/zjf280441589/article/details/52831029