模版方法模式(五)

一、初步了解模版方法模式

        假设需要定义一个汽车的模型,它有一些启动、引擎轰鸣、鸣笛、停止、行驶等方法。其中这个类可以定义如下:

public abstract class CarModel {
    //首先,这个模型要能发动起来
    public abstract void start();
    //能发动,还要能停下来
    public abstract void stop();
    //喇叭会出声音,是滴滴叫,还是哔哔叫
    public abstract void alarm();
    //引擎会轰隆隆地响,不响那是假的
    public abstract void engineBoom();
    //即使是模型应该也要能够行驶
    public void run(){
        this.start(); //先发动汽车
        this.engineBoom(); //引擎开始轰鸣
        this.alarm(); //然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
        this.stop(); //到达目的地就停车
    }
}

        其中 run() 方法就是一个模版方法,它是所有子类公共的部分代码,且定义了一系列基本方法的执行顺序(执行逻辑)。而 start()、stop() ... 等方法便是一系列子类去实现的基本方法,例如不同的车会有不同的启动方式、不同的鸣笛声音等等。


二、定义

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

        简单的说,就是父类定义一系列方法的执行流程,而这些方法由子类去实现。

注意:

        1.为了防止恶意操作,一般模版方法都加上 final 关键字,不允许被覆写。

        2.抽象模版中的基本方法尽量设计为 protected 类型,符合迪米特法则。


三、优点

        1.封装不变部分,扩展可变部分

        2.提取公共部分代码,便于维护

        3.行为由父类控制,子类实现


四、模版方法模式扩展——钩子函数

        针对上面的 CarModel 类,假如我们需要有的车辆在行驶的过程中不鸣笛,即需要在 run() 方法中控制是否鸣笛,这时候我们可以添加一个方法判断是否需要鸣笛,代码示例如下:

public abstract class CarModel {
    //首先,这个模型要能发动起来
    public abstract void start();
    //能发动,还要能停下来
    public abstract void stop();
    //喇叭会出声音,是滴滴叫,还是哔哔叫
    public abstract void alarm();
    //引擎会轰隆隆地响,不响那是假的
    public abstract void engineBoom();
    //即使是模型应该也要能够行驶
    public void run(){
        this.start(); //先发动汽车
        this.engineBoom(); //引擎开始轰鸣
        if (this.isAlarm()) {
            this.alarm(); //然后就开始跑了,跑的过程中遇到一条狗挡路,就按喇叭
        }
        this.stop(); //到达目的地就停车
    }
    //钩子方法,默认会鸣笛
    protected boolean isAlarm(){
        return true;
    }
}

        这里不需要鸣笛的车,只需要在子类中覆写 isAlarm() 方法并且返回 false 即可。

钩子函数:

        由外界条件的改变,影响到模版方法的执行,这种方法就叫做钩子函数(Hook Method)。有了钩子函数,我们就可以更灵活的控制模版方法的执行了。


五、应用场景

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

        2.重构时,模版方法是常使用的一个模式,把相同的代码抽取到父类中,然后可以通过钩子函数(下面介绍)约束其行为。


六、Android 开发中应用模版方法模式的一个实例

        Android 开发中基本离不开与 Activity 打交道,我们通常也会定义一个 BaseActivity 来定义所有 Activity 的一些共有特性,当然我们也可以定义一个这样的模版 BaseActivity,例如:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
 
public abstract class BaseActivity extends AppCompatActivity {
 
    protected final String TAG = this.getClass().getSimpleName();
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init(savedInstanceState);
    }
 
    private final void init(Bundle savedInstanceState) {
        setContentView();
        initData(savedInstanceState);
        initView();
    }
 
    // 子类在这个方法中完成绑定布局的实现
    protected abstract void setContentView();
 
    // 子类在这个方法中完成注册id,初始化布局的实现
    protected abstract void initView();
 
    // 子类在这个方法中完成初始化属性成员的实现
    protected abstract void initData(Bundle savedInstanceState);
 
}

        子类就可以像这样来写:

public class MainActivity extends BaseActivity implements View.OnClickListener {
 
    private TextView mToolbarTitleTv;
    private ImageView mToolbarSettingsIv;
    private Button mRegisterBtn;
    private Button mVerifyBtn;
 
    @Override
    protected void setContentView() {
        setContentView(R.layout.activity_main);
    }
     
    @Override
    protected void initView() {
        mToolbarTitleTv = (TextView) findViewById(R.id.toolbar_title_tv);
        mToolbarSettingsIv = (ImageView) findViewById(R.id.toolbar_settings_iv);
        mRegisterBtn = (Button) findViewById(R.id.register_btn);
        mVerifyBtn = (Button) findViewById(R.id.verify_btn);
        mToolbarTitleTv.setText(R.string.app_name);
        mToolbarSettingsIv.setVisibility(View.VISIBLE);
        mRegisterBtn.setOnClickListener(this);
        mVerifyBtn.setOnClickListener(this);
        mToolbarSettingsIv.setOnClickListener(this);
    }
 
    @Override
    protected void initData(Bundle savedInstanceState) {
        // TODO
    }
 
}


查看更多:设计模式分类以及六大设计原则

猜你喜欢

转载自blog.csdn.net/afei__/article/details/80472916