1. 模式介绍

模式的定义

定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模式的使用场景

多个子类有公有的方法,并且逻辑基本相同时。

重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。

重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。

2. UML类图

uml.png

角色介绍

AbstractClass : 抽象类,定义了一套算法框架。

ConcreteClass1 : 具体实现类1;

ConcreteClass2: 具体实现类2;

3. 模式的简单实现

简单实现的介绍

模板方法实际上是封装一个算法框架,就像是一套模板一样。而子类可以有不同的算法实现,在框架不被修改的情况下实现算法的替换。下面我们以开电脑这个动作来简单演示一下模板方法。开电脑的整个过程都是相对稳定的,首先打开电脑电源,电脑检测自身状态没有问题时将进入操作系统,对用户进行验证之后即可登录电脑,下面我们使用模板方法来模拟一下这个过程。

实现源码

package com.dp.example.templatemethod;

/**

* 抽象的Computer

* @author mrsimple

*

*/

public abstract class AbstractComputer {

protected void powerOn() {

System.out.println("开启电源");

}

protected void checkHardware() {

System.out.println("硬件检查");

}

protected void loadOS() {

System.out.println("载入操作系统");

}

protected void login() {

System.out.println("小白的电脑无验证,直接进入系统");

}

/**

* 启动电脑方法, 步骤固定为开启电源、系统检查、加载操作系统、用户登录。该方法为final, 防止算法框架被覆写.

*/

public final void startUp() {

System.out.println("------ 开机 START ------");

powerOn();

checkHardware();

loadOS();

login();

System.out.println("------ 开机 END ------");

}

}

package com.dp.example.templatemethod;

/**

* 码农的计算机

*

* @author mrsimple

*/

public class CoderComputer extends AbstractComputer {

@Override

protected void login() {

System.out.println("码农只需要进行用户和密码验证就可以了");

}

}

package com.dp.example.templatemethod;

/**

* 军用计算机

*

* @author mrsimple

*/

public class MilitaryComputer extends AbstractComputer {

@Override

protected void checkHardware() {

super.checkHardware();

System.out.println("检查硬件防火墙");

}

@Override

protected void login() {

System.out.println("进行指纹之别等复杂的用户验证");

}

}

package com.dp.example.templatemethod;

public class Test {

public static void main(String[] args) {

AbstractComputer comp = new CoderComputer();

comp.startUp();

comp = new MilitaryComputer();

comp.startUp();

}

}

输出结果如下 :

------ 开机 START ------

开启电源

硬件检查

载入操作系统

码农只需要进行用户和密码验证就可以了

------ 开机 END ------

------ 开机 START ------

开启电源

硬件检查

检查硬件防火墙

载入操作系统

进行指纹之别等复杂的用户验证

------ 开机 END ------

通过上面的例子可以看到,在startUp方法中有一些固定的步骤,依次为开启电源、检查硬件、加载系统、用户登录四个步骤,这四个步骤是电脑开机过程中不会变动的四个过程。但是不同用户的这几个步骤的实现可能各不相同,因此他们可以用不同的实现。而startUp为final方法,即保证了算法框架不能修改,具体算法实现却可以灵活改变。startUp中的这几个算法步骤我们可以称为是一个套路,即可称为模板方法。因此,模板方法是定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。如图 :

flow.png

4. Android源码中的模式实现

在Android中,使用了模板方法且为我们熟知的一个典型类就是AsyncTask了,关于AsyncTask的更详细的分析请移步Android中AsyncTask的使用与源码分析,我们这里只分析在该类中使用的模板方法模式。

在使用AsyncTask时,我们都有知道耗时的方法要放在doInBackground(Params... params)中,在doInBackground之前如果还想做一些类似初始化的操作可以写在onPreExecute方法中,当doInBackground方法执行完成后,会执行onPostExecute方法,而我们只需要构建AsyncTask对象,然后执行execute方法即可。我们可以看到,它整个执行过程其实是一个框架,具体的实现都需要子类来完成。而且它执行的算法框架是固定的,调用execute后会依次执行onPreExecute,doInBackground,onPostExecute,当然你也可以通过onProgressUpdate来更新进度。我们可以简单的理解为如下图的模式 :

async-flow.png

下面我们看源码,首先我们看执行异步任务的入口, 即execute方法 :

public final AsyncTask execute(Params... params) {

return executeOnExecutor(sDefaultExecutor, params);

}

public final AsyncTask 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接口,并添加了一个参数数组字段,我们挨个来分析吧,跟踪代码我们可以看到,这两个字段都是在构造函数中初始化。

public AsyncTask() {

mWorker = new WorkerRunnable() {

public Result call() throws Exception {

mTaskInvoked.set(true);

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

return postResult(doInBackground(mParams));

}

};

mFuture = new FutureTask(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(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 {

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的模板方法。

5. 构建整个应用的BaseActivity

接下来我们看一下怎么才能用到开发中... 等等我要去举报你 --> 怎么啦? 你抄袭别人的。怎么?被发现了吗,我这不是抄袭只是把好东西拿出来与大家分享而已,给大家推荐一下:https://github.com/simple-android-framework-exchange/android_design_patterns_analysis#schedule 里面有很多设计模式,最好大家可以买一本书看一下这么好的东西还是支持一下吧希望可以出一些更好的(虽然我看的是电子文档)。说到这里非常感谢大家的打赏虽然不多但是我内心真的很感谢,希望以后可以出更多好的文章。

在网上查了很多关于别人讲的模板设计模式,都是只简单的介绍一下概念然后写一个小的事例如:程序员的一天,银行办理业务等等等等。我最近剃了个光头,因为上班闲来无事看别人的博客的时候老是抓头发,一直都在想想我该用到哪里呢?哪里又能用到呢?.......所以干脆剃了个光头。

因为目前还是停留在内涵段子项目的系统架构部分,而且每个项目肯定离不开Activity,在Activity的onCreate()方法里面基本都是:设置布局 ->初始化头部 -> 初始化界面 -> 初始化数据。如果按照这么个流程是不是刚好符合我们模板设计模式。

/**

* Created by Darren on 2017/2/8.

* Email: 240336124@qq.com

* Description: 整个应用的BaseActivity

*/

public abstract class BaseActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView();

initTitle();

initView();

initData();

}

// 初始化数据

protected abstract void initData();

// 初始化界面

protected abstract void initView();

// 设置界面视图

protected abstract void setContentView();

// 初始化头部

protected abstract void initTitle();

}

以后我们每次新建Activity就不会直接继承自 AppCompatActivity 而是我们自己的BaseActivity就会自动要我们复写BaseActivity里面的几个抽象方法,我们在方法里面写对应的代码。

/**

* Created by Darren on 2017/2/8.

* Email: 240336124@qq.com

* Description: 主页面MainActivity

*/

public class MainActivity extends BaseActivity {

@Override

protected void initData() {

}

@Override

protected void initView() {

}

@Override

protected void setContentView() {

setContentView(R.layout.activity_main);

}

@Override

protected void initTitle() {

}

}

这也没见到什么好处啊~好处我待会再来说,我们先对BaseActivity来扩展一下,一些通用的流程和功能其实可以放在BaseActivity里面,比如前几次所分享的自己动手打造一套IOC注解框架、启动Activity...

/**

* Created by Darren on 2017/2/8.

* Email: 240336124@qq.com

* Description: 整个应用的BaseActivity

*/

public abstract class BaseActivity extends AppCompatActivity {

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView();

// IOC注解注入

ViewUtils.inject(this);

initTitle();

initView();

initData();

}

// 初始化数据

protected abstract void initData();

// 初始化界面

protected abstract void initView();

// 设置界面视图

protected abstract void setContentView();

// 初始化头部

protected abstract void initTitle();

/**

* 启动一个Activity

* @param activity 需要启动的Activity的Class

*/

public void startActivity(Class extends Activity> activity) {

Intent intent = new Intent(this,activity);

startActivity(intent);

}

/**

* findViewById 不需要再去强转

*/

public T viewById(@IdRes int resId) {

return (T) super.findViewById(resId);

}

}

接下来我们来说一下好处,模板设计模式的好处就不说了网上太多了,我们就只说在真正的开发中这么做的好处

在实际的开发过程中我们往往不是一个人在开发,如果把直接在onCreate()里面写很多东西显然不行,但是如果写一些方法,那么每个成员所写的方法都会不同,何况有些哥们英语估计没过四级,单词都写错;

直接继承自BaseActivity会自动提示覆盖方法,更加有利于开发或者代码的阅读,每个方法各尽其职只干自己该干的事,没事干就歇着;

我们可以把通用的流程或者是某些方法放到BaseActivity,这样又节省代码又方便但是不是乱七八糟的放一大堆,细节会有很多具体可以看视频讲解;

我们中间肯定还需要逻辑层的BaseActivity,这样做其实有利于后期的版本迭代、层次抽离和代码重构...

android 程序类图,Android模板设计模式之 - 构建整个应用的BaseActivity相关推荐

  1. android 继承类图,Android Studio中绘制UML类图介绍

    Android Studio中绘制UML类图介绍 Android Studio中绘制UML类图介绍 动机 最近开始阅读项目源码,从其中一个模块开始看,奈何大项目中的一个模块,对于萌新而言,也太过于复杂 ...

  2. java写一个android程序_【Android开发笔记】3.编写第一个Android程序

    前言 上一节我们通过一个Demo熟悉了Eclipse的基本使用.如何在模拟器和手机中运行以及如何打包成APK,但没具体编写代码,相信很多同学已经按耐不住了吧,这一节我们会动手编写代码来熟悉Androi ...

  3. 如何在类图中标注设计模式(二)

    接文章<如何在类图中标注设计模式(一)>. 本文姗姗来迟,见谅!        5.  基于标记的模式标注 美国德克萨斯大学达拉斯分校的Jing Dong等人提出了一种基于标记的模式标注方 ...

  4. java备忘录模式 类图,Android编程设计模式之备忘录模式详解

    本文实例讲述了Android编程设计模式之备忘录模式.分享给大家供大家参考,具体如下: 一.介绍 备忘录模式是一种行为模式,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态,这有点像我们平时 ...

  5. Android UML类图介绍及画法

    转载于:http://uule.iteye.com/blog/2078935 继承.实现是三角型箭头,其他都为箭头 组合.聚合都有一个菱形端,且都为实线,其他都无菱形端 继承是实线,实现是虚线 关联是 ...

  6. android应用程序框架图,Android系统框架图详解

    Android系统从下至上分为4层:Linux内核.Android程序库及Android运行时.Android应用程序框架,以及应用程序等. 图1-1 Android系统框架 1. Linux内核(L ...

  7. android程序启动动画,Android设置软件启动动画(以及初次安装的几张引导图)

    Android设置软件启动动画(以及初次安装的几张引导图) 设置软件启动动画 1 创建一个启动Activity 这里叫做QiDongActivity 它的XML中设置一个matchparent的背景图 ...

  8. android 程序崩溃处理,Android应用崩溃的应急处理

    在我们开发Android应用程序的时候总是难免遇到程序崩溃的问题:(很抱歉,"××"已停止运行.) 每次看到这个问题心都是哇凉哇凉的 一般遇到这样问题,有两种可能: 1.自己的代码 ...

  9. android程序开发教案,Android移动应用开发基础教程教案.doc

    教 案 课 程 名 称Android移动应用开发基础教程(微课版)课 程 代 码系(部)教研室(实验室)授 课 教 师职 称 年 月 课 程 名 称Android移动应用开发基础教程(微课版)总计: ...

最新文章

  1. 前端学习(3237):react生命周期4
  2. Charles - 接口抓包分析工具
  3. 关于二维数组取地址加以或减一解引用问题
  4. 专业课程设计之客户与服务器程序的同步与通信机制的设计(二)TCP通信
  5. 100999凑整到万位进一_四年级数学第一单元练习作业
  6. 大数据在智慧社区的作用有哪些
  7. 【SimpleITK】医疗影像分割结果评价指标计算
  8. WC2013 糖果公园
  9. .NET Remoting 配置文件方式
  10. 联想拯救者y7000电池耗电快_联想拯救者Y7000P使用一周体验
  11. java 调用微信JsApi支付
  12. 电子罗盘的椭球拟合与椭球变换
  13. Arm 虚拟硬件与新解决方案或将颠覆物联网产品研发
  14. 【Python从0到1】第三篇:基础语法(三)
  15. 【HTML】铺满背景图片
  16. JavaSE--Set接口
  17. oauth2-怎么使用
  18. CSS加载外部字体以及字体格式转换
  19. 【深度学习前沿应用】目标检测
  20. Centos下jira、confluence利用nginx 代理配置为统一入口

热门文章

  1. 看微软 Windows 30年发展简史,你用过最早的系统版本是什么?
  2. B-Tree和B+tree
  3. html点击圆点箭头分页,css实现小箭头的实现方式
  4. node爬取app数据_在电销行业中,运营商大数据究竟起着怎样的作用
  5. k8s往secret里导入证书_Rancher 修改Kubernetes Ingress默认ssl证书
  6. 【若依(ruoyi)】自定义的数据选择对话框
  7. 【Mybatis】 mapper XML 文件中使用 association 实现一对一关联
  8. csgo服务器linux云崖居,CSGO修改地图天气背景指令
  9. php操作xml文件,php xml文件操作代码(一)
  10. arduino 嗡鸣器 音乐_[求助]怎样实现红外遥控蜂鸣器播放音乐,求大神指正