Template Method概述
UML概述
玩具代码案例 - 基于模板模式的登录服务
模板主体
模板模式的主体提供了稳定的业务流程,不稳定的逻辑由子类来实现
package online.javabook.gof.behavioral.patterns9.template2.login.service;
public abstract class LoginService {
// template method
public void login(String userName, String password) {
boolean isOK = checkAccount(userName, password);
if(isOK) {
handlerLogin(userName);
}else{
handlerError(userName);
}
}
protected abstract boolean checkAccount(String userName, String password);
protected abstract void handlerLogin(String userName);
protected abstract void handlerError(String userName);
}
模板实现
FacebookLoginService
package online.javabook.gof.behavioral.patterns9.template2.login.template;
import online.javabook.gof.behavioral.patterns9.template2.login.service.LoginService;
public class FacebookLoginService extends LoginService {
@Override
protected boolean checkAccount(String userName, String password) {
System.out.println("Check Facebook account");
return true;
}
@Override
protected void handlerLogin(String userName) {
System.out.println("send a Facebook login message");
}
@Override
protected void handlerError(String userName) {
System.out.println("send a Facebook error message");
}
}
GoogleLoginService
package online.javabook.gof.behavioral.patterns9.template2.login.template;
import online.javabook.gof.behavioral.patterns9.template2.login.service.LoginService;
public class GoogleLoginService extends LoginService {
@Override
protected boolean checkAccount(String userName, String password) {
System.out.println("Check Google account");
return true;
}
@Override
protected void handlerLogin(String userName) {
System.out.println("send a Google login message");
}
@Override
protected void handlerError(String userName) {
System.out.println("send a Google error message");
}
}
YouTubeLoginService
package online.javabook.gof.behavioral.patterns9.template2.login.template;
import online.javabook.gof.behavioral.patterns9.template2.login.service.LoginService;
public class YouTubeLoginService extends LoginService {
@Override
protected boolean checkAccount(String userName, String password) {
System.out.println("Check YouTube account");
return true;
}
@Override
protected void handlerLogin(String userName) {
System.out.println("send a youtube login message");
}
@Override
protected void handlerError(String userName) {
System.out.println("send a youtube error message");
}
}
不基于模板模式的实现
Main
package online.javabook.gof.behavioral.patterns9.template2.login.app.bad;
public class Main {
public static void main(String[] args) {
String social = "google";
String userName = "xxx";
String password = "yyy";
switch (social) {
case "google":{
boolean isOK = checkGoogleAccount(userName, password);
if(isOK) {
handlerGoogleLogin(userName);
}else{
handlerGoogleError(userName);
}
break;
}
case "facebook":{
boolean isOK = checkFacebookAccount(userName, password);
if(isOK) {
handlerFacebookLogin(userName);
}else{
handlerFacebookError(userName);
}
break;
}
case "youtube":{
boolean isOK = checkYoutubeAccount(userName, password);
if(isOK) {
handlerYoutubeLogin(userName);
}else{
handlerYoutubeError(userName);
}
break;
}
default:
throw new IllegalStateException("Unexpected value: " + social);
}
}
// -----------------------------------------------------
protected static boolean checkFacebookAccount(String userName, String password) {
System.out.println("Check Facebook account");
return true;
}
protected static void handlerFacebookLogin(String userName) {
System.out.println("send a Facebook login message");
}
protected static void handlerFacebookError(String userName) {
System.out.println("send a Facebook error message");
}
// -----------------------------------------------------
protected static boolean checkGoogleAccount(String userName, String password) {
System.out.println("Check Google account");
return true;
}
protected static void handlerGoogleLogin(String userName) {
System.out.println("send a Google login message");
}
protected static void handlerGoogleError(String userName) {
System.out.println("send a Google error message");
}
// -----------------------------------------------------
protected static boolean checkYoutubeAccount(String userName, String password) {
System.out.println("Check YouTube account");
return true;
}
protected static void handlerYoutubeLogin(String userName) {
System.out.println("send a youtube login message");
}
protected static void handlerYoutubeError(String userName) {
System.out.println("send a youtube error message");
}
}
Console
Check Google account
send a Google login message
基于模板模式的实现
Main
package online.javabook.gof.behavioral.patterns9.template2.login.app.good;
import online.javabook.gof.behavioral.patterns9.template2.login.service.LoginService;
import online.javabook.gof.behavioral.patterns9.template2.login.template.FacebookLoginService;
import online.javabook.gof.behavioral.patterns9.template2.login.template.GoogleLoginService;
import online.javabook.gof.behavioral.patterns9.template2.login.template.YouTubeLoginService;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String loginType = "google";
Map<String, LoginService> loginServiceRegister = new HashMap<>();
loginServiceRegister.put("google", new GoogleLoginService());
loginServiceRegister.put("facebook", new FacebookLoginService());
loginServiceRegister.put("youtube", new YouTubeLoginService());
LoginService loginService = loginServiceRegister.get(loginType);
loginService.login("xxx", "yyy");
}
}
Console
Check Google account
send a Google login message
显示世界中的模板模式
Hadoop中的Mapper和Reducer类
mapper和reducer中的run方法定义好了程序的主体处理逻辑,中间的每一步要做什么和怎么做,比如setup,map/reduce, cleanup的调用和循环处理。 但是具体setup,map/reduce, cleanup怎么做就交给了子类来实现。就好像定义了一个代码表格,只要无脑的填写这个代码表格中的逻辑就可以了,具体底层做了什么不用关心。
package org.apache.hadoop.mapreduce;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.RawComparator;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.mapreduce.task.MapContextImpl;
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
/**
* The <code>Context</code> passed on to the {@link Mapper} implementations.
*/
public abstract class Context
implements MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
}
/**
* Called once at the beginning of the task.
*/
protected void setup(Context context
) throws IOException, InterruptedException {
// NOTHING
}
/**
* Called once for each key/value pair in the input split. Most applications
* should override this, but the default is the identity function.
*/
@SuppressWarnings("unchecked")
protected void map(KEYIN key, VALUEIN value,
Context context) throws IOException, InterruptedException {
context.write((KEYOUT) key, (VALUEOUT) value);
}
/**
* Called once at the end of the task.
*/
protected void cleanup(Context context
) throws IOException, InterruptedException {
// NOTHING
}
/**
* Expert users can override this method for more complete control over the
* execution of the Mapper.
* @param context
* @throws IOException
*/
public void run(Context context) throws IOException, InterruptedException {
setup(context);
try {
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
} finally {
cleanup(context);
}
}
}
package org.apache.hadoop.mapreduce;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.task.annotation.Checkpointable;
import java.util.Iterator;
@Checkpointable
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
/**
* The <code>Context</code> passed on to the {@link Reducer} implementations.
*/
public abstract class Context
implements ReduceContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
}
/**
* Called once at the start of the task.
*/
protected void setup(Context context
) throws IOException, InterruptedException {
// NOTHING
}
/**
* This method is called once for each key. Most applications will define
* their reduce class by overriding this method. The default implementation
* is an identity function.
*/
@SuppressWarnings("unchecked")
protected void reduce(KEYIN key, Iterable<VALUEIN> values, Context context
) throws IOException, InterruptedException {
for(VALUEIN value: values) {
context.write((KEYOUT) key, (VALUEOUT) value);
}
}
/**
* Called once at the end of the task.
*/
protected void cleanup(Context context
) throws IOException, InterruptedException {
// NOTHING
}
/**
* Advanced application writers can use the
* {@link #run(org.apache.hadoop.mapreduce.Reducer.Context)} method to
* control how the reduce task works.
*/
public void run(Context context) throws IOException, InterruptedException {
setup(context);
try {
while (context.nextKey()) {
reduce(context.getCurrentKey(), context.getValues(), context);
// If a back up store is used, reset it
Iterator<VALUEIN> iter = context.getValues().iterator();
if(iter instanceof ReduceContext.ValueIterator) {
((ReduceContext.ValueIterator<VALUEIN>)iter).resetBackupStore();
}
}
} finally {
cleanup(context);
}
}
}