1.模板方法模式

模板方法模式是一种行为型设计模式。它定义一个算法骨架,而将一些步骤延迟到子类中,即在父类中编排主流程,将步骤实现延迟到子类去实现。模板方法使得子类可以在不改变算法的结构下,重定义该算法的某些特定步骤。

此模式总结概括就是流程封装,也就是把某个固定的流程封装到一个final方法中,并且让子类能够定制这个流程中的某些或所有步骤,这就要求父类提取公用的代码,提升代码的复用率,同时带来了更好的可扩展性。

 

UML类图:

Android 模块化如何新建相似模块 android模型_Android 模块化如何新建相似模块

抽象父类AbstractClass:实现了模板方法,定义了一套算法框架。

具体实现类ConcreteClass1、ConcreteClass2:实现抽象类中的抽象方法,即不同的对象的具体实现细节。

 

使用场景:

①算法的整体步骤很固定,但其中个别部分易变时,可使用模板方法模式将容易变化的部分抽象出来,供子类去实现。

②当多个子类有公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。

当需要控制子类的扩展时,模板方法模式在特定点调用钩子方法,使用钩子方法让子类决定父类的某个步骤是否执行,实现子类对父类的反向控制。

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

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

 

模板方法模式优点:

①提高代码复用性,将相同部分的代码放在抽象的父类中,而不同的代码放入不同的子类中。

②实现了反向控制一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制,符合开闭原则。

缺点:

①每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

 

2.模板方法模式的实现

抽象模板:

public abstract class AbstractTemplate {
    //模板方法
    public void templateMethod() {
        doOperation1();
        if(isNeedOperation2) {
            doOperation2();
        }
        doOperation3();
    }
    // 基本方法--抽象方法
    protected abstract void doOperation1();
    // 基本方法
    protected void doOperation2() {
        // 空实现,子类实现
    }
    // 基本方法-具体方法由抽象类声明并实现,而子类并不实现或置换
    protected void doOperation3() {
        // 业务逻辑省略..
    }
    //钩子方法,是否需要第二步,默认需要
    protected boolean isNeedOperation2(){
        return true; //使用钩子方法让子类决定父类的某个步骤是否执行,实现子类对父类的反向控制
    }
}

具体模板:

public class ConcreteTemplateA extends AbstractTemplate {
    @Override
    protected void doOperation1() {
        // 业务逻辑省略..
    }
    @Override
    protected void doOperation2() {
        // 业务逻辑省略..
    }
    protected boolean isNeedOperation2(){
        return true; 
    }
}
public class ConcreteTemplateB extends AbstractTemplate {
    @Override
    protected void doOperation1() {
        // 业务逻辑省略..
    }
    @Override
    protected void doOperation2() {
        // 业务逻辑省略..
    }
    protected boolean isNeedOperation2(){
        return false; //该子类的算法不需要第二步
    }
}

客户端:

ConcreteTemplateA aa = new ConcreteTemplateA();
ConcreteTemplateB bb = new ConcreteTemplateB();
aa.templateMethod();
bb.templateMethod();

 

在Android开发中,每一个activity都会有很多相同的方法,例如初始化界面、初始化数据、设置相同的主题等。这时候就可以使用模板方法模式来优化。

①新建一个BaseActivity基类,在里面定义算法框架

public abstract class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);       
    }
    //模板方法,多个基本方法的组合
    public final void firstInit{
        setContentView(initLayout()); 
        initView();
        if(isInitData()) { //钩子方法
            initData();
        }
    }
    //基本方法,模板方法里面调用
    protected abstract int initLayout(); 
    protected abstract void initData(); 
    protected abstract void initView(); 
    //钩子方法,是否要初始化数据,默认为true
    protected boolean isInitData() {
        return true;
    }
}

把setContentView()方法放在了父类中,在每一个子类传入布局id就可以了。

定义了一个钩子方法,当默认需要初始化数据时,什么都不用改动;如果不需要初始化数据,只需要覆写钩子方法isInitData并返回false即可。

②子类

public class TestActivity extends BaseActivity {
    @Override
    protected int initLayout() {
        return R.layout.activity_test;
    }
    @Override
    protected void initView() {
        //本activity的findViewById()等操作
    }
    @Override
    protected void initData() {
        //本activity的初始化数据
    }
}

模板方法实际上是封装一个固定流程,就像一套固定模板一样,第一步该做什么,第二步该做什么都已经在抽象类中定义好。而子类可以有不同的算法实现,在框架不被修改的情况下实现某些步骤的算法替换。

注意:

1)父类中的基本方法尽量设计为protected,符合迪米特原则。

2)父类中的模板方法一般设置为final,不允许子类重写。目的一是为了避免子类恶意操作,二是为了模板的共性。

 

3.Android源码中的模板方法模式

①AsyncTask

在使用AsyncTask时,把耗时操作放到doInBackground(Params… params)中,在doInBackground之前,如果想做一些初始化操作,可以把实现写在onPreExecute中,当doInBackground执行完后会执行onPostExecute方法,而我们只需要构建AsyncTask对象,然后执行execute方法。

②Activity的生命周期

ActivityThread的main函数被调用后,依次执行Activity的onCreate、onStart、onResume函数,用户通常在Activity的子类中覆写onCreate方法,并且在该方法中调用setContentView来设置布局。