设计模式专栏
1.定义:
定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
2.使用场景
1.多个子类有公有的方法,并且逻辑基本相同
2.重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
3.重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为
3.UML建模图
AbsTemplate:抽象类,定义了一套算法框架
ConcreteImplA: 具体实现类A
ConcreteImplB: 具体实现类B
4.模板方法模式简单实现
以电脑开机到关机整个过程作为模板,这里面包括如下过程,开机-->加载系统-->用户登录--->关机
而具体的针对2中不同的电脑,Windows和MAC,这里定义Windows用户登录是输入用户名和密码,而MAC用户登录则是验证指纹,所以,整个核心流程是相同的,但是2中操作系统的用户登录的方法不同,即:
- 电脑抽象类
public abstract class AbstractComputer {
/**
* 开机
*/
protected void powerOn(){
System.out.println("开启电源");
}
protected void loadOS(){
System.out.println("加载操作系统");
}
protected void login(){
System.out.println("小白进入系统,无需登录");
}
//注意这里使用了final防止子类修改算法步骤
public final void startUp(){
System.out.println("===开机===");
powerOn();
loadOS();
login();
System.out.println("===关机===");
}
}
- Windows电脑实现
public class WinComputer extends AbstractComputer {
@Override
protected void login() {
System.out.println("windows输入用户名和密码进入系统了");
}
}
- MAC电脑实现
public class MacComputer extends AbstractComputer {
@Override
protected void login() {
System.out.println("mac验证指纹识别进入系统了");
}
}
- 最终测试
public class Test {
public static void main(String[] args) {
AbstractComputer winComputer=new WinComputer();
winComputer.startUp();
AbstractComputer macComputer=new MacComputer();
macComputer.startUp();
}
}
-
测试结果
5.模板方法在Android中的使用
相信做Android开发的同学,在前几年还没有出现这么多好用的框架的时候,网络请求或者大量IO流操作一定离不开AsyncTask,它给我们提供了非常简便的用法,个人感觉是Rxjava的前身,该类则通过依次执行onPreExecute、doInBackground、onPostExecute的算法框架,来实现网络请求或者IO操作等。
- 简单看一下AsyncTask的源码
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
- 在execute()方法中看到执行了executeOnExecutor(sDefaultExecutor, params);方法,在跟进查看executeOnExecutor()方法如下:
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
-
从这里可以看到首先执行了onPreExecute();然后将参数封装给mWorker对象和mFuture对象,之后调用了exec.execute(mFuture),开始执行真正的耗时操作。
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
通过查看Executor源码,可以看到execute()方法中的参数为Runnable类型,即mFuture为Runnable实现类,即done()方法可以理解为run()方法,又因为FutureTask的参数为mWorker,则间接执行到mWorker中的方法即doInbackground()方法,即处理耗时操作,将返回的结果,通过postResultIfNotInvoked(get())方法,通过handler切换到主线程。
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Result result = null;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
result = doInBackground(mParams);
Binder.flushPendingCommands();
} catch (Throwable tr) {
mCancelled.set(true);
throw tr;
} finally {
postResult(result);
}
return result;
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occurred while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
简单的说:mFuture包装了mWorker对象,然后通过调用mFuture中的run()方法,简介调用了mWorker中的call方法,在call方法中又调用了doInBackground()方法,因为mFuture提交了线程池来执行,所以doInBackground()方法执行在非UI线程中,得到doInbackground的结果后,通过postResult传递出结果给UI线程
6.总结
execute方法中封装了onPreExecute()、doInbackground()、onPostExecute()模板算法,用户根据自己的需求,复写相关方法,使得用户很方便的使用异步任务来完成耗时的操作及更新UI,其实是通过线程池来执行耗时的任务,得到结果后,通过handler将结果传递到UI线程来执行。