浅析设计模式之模板模式
2015-04-18 22:32
183 查看
浅析设计模式之模板模式
定义
In software engineering, the template method pattern is a behavioral design pattern that defines the program skeleton of an algorithm in a method, called template method, which defers some steps to subclasses. It lets one redefine certain steps of an algorithm without changing the algorithm’s structure.软件工程中,模板模式是活动型设计模式,在一个方法中定义了程序的轮廓结构,这个方法成为模板方法,将一些实现交给子类进行处理。这使程序员自己处理需要变化的算法,但并不会改变算法的整体结构
对模板模式的理解
模板模式主要通过一个模板方法来进行实现。这个方法已经有了执行的具体步骤,即算法轮廓。但是由于有的步骤中是由差异的,那么可以将这些步骤抽取出来为一个抽象的方法,让子类进行具体实现。模板模式适合定义一群具有相同步骤类的父类,因为这样可以在新建子类时而不同重复以前已经存在的代码了,实现了代码的复用,同时也确保了代码结构的准确性
模式的使用场景
多个子类有公有的方法,并且逻辑基本相同时。重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
uml图
角色分析
AbstractClass: 封装了算法结构,将变化抽象,将不变的实例ConcreteClass: 实现抽象类,将变化进行实现
Hook, 抽象父类的实例方法,可以被子类覆盖
Hook的分析
Hook是个实例方法,是程序员可选实现的方法,通常在父类是空的如果父类实例方法不能被覆盖,需要使用private标记符,以此是它不可更改,可以在模板方法加入final前缀,使其不能被子类覆盖
模板方法命名规则
In order to identify the primitive methods is it better to use a specific naming convention. For example the prefix “do” can be used for primitive methods. In a similar way the customizations hooks can have prefixes like “pre” and “post”.可以使用do前缀标记这个方法是需要实现的抽象方法,用pre或者post标记这个方法是个hook
模板模式与策略模式的区别
策略模式封装了各个同种类型的算法类模板模式定义了模板方法的结构,使需要实现的方法抽象出来供子类实现
在使用中,策略模式使用的是代理,而模板模式使用的是继承
项目中使用过的代码
public abstract class BaseActivity extends Activity implements OnHeaderClickListener, OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); autoInitView(); initHeaderView(); initComponents(); } public abstract void initHeaderView(); public abstract void initComponents(); public void autoInitView() { AutoViewInitializer.newInstance(this).startInit(); } public abstract int getLayoutId(); @Override public abstract void onClick(View v); @Override public abstract void OnHeaderClick(View v, int option); }
Android源码中的模式实现
在Android中,使用了模板方法且为我们熟知的一个典型类就是AsyncTask了,关于AsyncTask的更详细的分析请移步Android中AsyncTask的使用与源码分析,我们这里只分析在该类中使用的模板方法模式。在使用AsyncTask时,我们都有知道耗时的方法要放在doInBackground(Params… params)中,在doInBackground之前如果还想做一些类似初始化的操作可以写在onPreExecute方法中,当doInBackground方法执行完成后,会执行onPostExecute方法,而我们只需要构建AsyncTask对象,然后执行execute方法即可。我们可以看到,它整个执行过程其实是一个框架,具体的实现都需要子类来完成。而且它执行的算法框架是固定的,调用execute后会依次执行onPreExecute,doInBackground,onPostExecute,当然你也可以通过onProgressUpdate来更新进度。我们可以简单的理解为如下图的模式 :
下面我们看源码,首先我们看执行异步任务的入口, 即execute方法 :
public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); } 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; }
可以看到execute方法(为final类型的方法)调用了executeOnExecutor方法,在该方法中会判断该任务的状态,如果不是PENDING状态则抛出异常,这也解释了为什么AsyncTask只能被执行一次,因此如果该任务已经被执行过的话那么它的状态就会变成FINISHED。继续往下看,我们看到在executeOnExecutor方法中首先执行了onPreExecute方法,并且该方法执行在UI线程。然后将params参数传递给了mWorker对象的mParams字段,然后执行了exec.execute(mFuture)方法。
mWorker和mFuture又是什么呢?其实mWorker只是实现了Callable接口,并添加了一个参数数组字段,关于Callable和FutureTask的资料请参考Java中的Runnable、Callable、Future、FutureTask的区别与示例,我们挨个来分析吧,跟踪代码我们可以看到,这两个字段都是在构造函数中初始化。
public AsyncTask() { mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { mTaskInvoked.set(true); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); return postResult(doInBackground(mParams)); } }; mFuture = new FutureTask<Result>(mWorker) { @Override protected void done() { try { final Result result = get(); postResultIfNotInvoked(result); } catch (InterruptedException e) { android.util.Log.w(LOG_TAG, e); } catch (ExecutionException e) { throw new RuntimeException("An error occured while executing doInBackground()", e.getCause()); } catch (CancellationException e) { postResultIfNotInvoked(null); } catch (Throwable t) { throw new RuntimeException("An error occured while executing " + "doInBackground()", t); } } }; }
简单的说就是mFuture就包装了这个mWorker对象,会调用mWorker对象的call方法,并且将之返回给调用者。
关于AsyncTask的更详细的分析请移步Android中AsyncTask的使用与源码分析,我们这里只分析模板方法模式。总之,call方法会在子线程中调用,而在call方法中又调用了doInBackground方法,因此doInBackground会执行在子线程。doInBackground会返回结果,最终通过postResult投递给UI线程。
我们再看看postResult的实现 :
private Result postResult(Result result) { Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; } private static class InternalHandler extends Handler { @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"}) @Override public void handleMessage(Message msg) { AsyncTaskResult result = (AsyncTaskResult) msg.obj; switch (msg.what) { case MESSAGE_POST_RESULT: // There is only one result result.mTask.finish(result.mData[0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate(result.mData); break; } } } private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
可以看到,postResult就是把一个消息( msg.what == MESSAGE_POST_RESULT)发送给sHandler,sHandler类型为InternalHandler类型,当InternalHandler接到MESSAGE_POST_RESULT类型的消息时就会调用result.mTask.finish(result.mData[0])方法。我们可以看到result为AsyncTaskResult类型,源码如下 :
@SuppressWarnings({"RawUseOfParameterizedType"}) private static class AsyncTaskResult<Data> { final AsyncTask mTask; final Data[] mData; AsyncTaskResult(AsyncTask task, Data... data) { mTask = task; mData = data; } }
可以看到mTask就是AsyncTask对象,调用AsyncTask对象的finish方法时又调用了onPostExecute,这个时候整个执行过程就完成了。
总之,execute方法内部封装了onPreExecute, doInBackground, onPostExecute这个算法框架,用户可以根据自己的需求来在覆写这几个方法,使得用户可以很方便的使用异步任务来完成耗时操作,又可以通过onPostExecute来完成更新UI线程的工作。
另一个比较好的模板方法示例就是Activity的声明周期函数,例如Activity从onCreate、onStart、onResume这些程式化的执行模板,这就是一个Activity的模板方法。
优点
封装不变部分,扩展可变部分,减少重复代码量提取公共部分代码,便于维护
缺点
模板方法会带来代码阅读的难度,会让心觉得难以理解。相关文章推荐
- 设计模式之模板方法浅析
- 设计模式浅析之--模板方法模式Template Method
- 浅析设计模式之模板方法
- 设计模式之模板方法浅析
- java设计模式之模板方法模式
- 设计模式-模板模式
- 设计模式之模板方法模式
- 求一段代码运行时所花费的时间(模板设计方法设计模式)
- Android设计模式之模板方法模式
- Android设计模式之(14)----模板模式
- 从Spring HibernateTemplate模板方法设计模式的实现谈起
- 设计模式学习---第五节:模板模式
- 设计模式之--模板方法模式(抓住问题的核心)
- 设计模式 - 行为型模式 - 模板方法模式
- spring_HibernateTemplate(Hibernate模板)_模版设计模式
- 12. 星际争霸之php设计模式--模板模式
- 设计模式之模板方法模式
- 设计模式--模板模式
- 设计模式之模板方法模式
- 【设计模式】之 Template 模板方法