一. 模板模式
在日常面向对象开发过程中,有时候会有这样的需求:某一算法或是业务逻辑的实现过程中,我们知道关键步骤,并且确定这些步骤的执行顺序;但是,个别/某些步骤的具体实现是未知的(会随着不同的环境或者条件的变化而变化),此时我们便可以使用模板模式来应对这种情况,既满足了需求,同时还能提高代码的复用性和代码结构的灵活性。
-
定义:在定义一个操作的算法框架时,将一些步骤延时到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤。
模板模式.png
AbstractClass:抽象类,定义了一套算法框架。
ConcreteClass:具体实现类。
这个抽象类包含了3种类型的方法,分别是抽象方法、具体方法和钩子方法。抽象方法是交由子类去实现的,具体方法则是父类实现了子类公共的方法,钩子方法hook()是一个默认空实现的方法。
-
模板方法模式的使用场景和优缺点
(1)使用场景:
• 多个子类有共有的方法,并且逻辑基本相同时。
• 面对重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能则由各个子类实现。
• 需要通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。
(2)优点:
• 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。
• 子类实现算法的某些细节,有助于算法的扩展。
(3)缺点:
• 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。 -
一个简单的例子
大致情景:在忙碌了一天之后,彪志伟下班回家,回家后做一些事情,事情完成之后再睡觉休息;从上述情景中我们可以获取以下的几点信息:
(1)下班回家:可以坐地铁,也可以步行、开车等等;
(2)回家之后所作的事情:平时大多情况下是自己自由支配,但也有可能出现特殊情况需要在家加班;
(3)在完成(2)中的事情之后,洗漱睡觉;
抽象类的代码如下:
package com.example.tcl.myapplication.baselib;
public abstract class AfterWork{
//定义为final,不允许外部修改算法的结构
public final void execute(){
goHome();
doSomething();
goSleeping();
}
//钩子方法,空实现
protected void hook(){}
protected abstract void goHome();
protected abstract void goSleeping();
protected abstract void work();
protected void doSomething(){
if(isNeedWorking()){
work();
}
}
//钩子方法,是否需要加班,默认不加班
protected boolean isNeedWorking(){
return false;
}
}
以彪志伟为例继承AfterWork类,代码如下:
package com.example.tcl.myapplication.baselib;
import android.util.Log;
public class BzwAfterWork extends AfterWork {
private String TAG = "BzwAfterWork";
@Override
protected void goHome() {
Log.i(TAG, "骑着我的宝驴牌电动车回家");
}
@Override
protected void doSomething() {
super.doSomething();
Log.i(TAG, "打开冰箱,拿出一瓶宅男快乐水;开电脑看b站...");
}
@Override
protected void goSleeping() {
Log.i(TAG, "11点了,洗澡睡觉");
}
@Override
protected void work() {
//默认不加班,如果需要加班,则重写父类isNeedWorking()方法,返回true;
}
}
使用:
BzwAfterWork bzwAfterWork = new BzwAfterWork();
bzwAfterWork.execute();
运行结果:
07-23 10:47:31.286 4097-4097/? I/BzwAfterWork:
骑着我的宝驴牌电动车回家
打开冰箱,拿出一瓶宅男快乐水;开电脑看b站...
11点了,洗澡睡觉
二. BaseActivity的封装
作为Acitvity的基类,主要是用来实现Activity的一些公共属性以及公共方法,在一定程度上优化代码结构,降低耦合度,提高代码可读性,方便修改和拓展;把具体的功能写成具体的方法实现,而对于某一方法的逻辑需求不确定或者具体操作不明确时写成抽象方法交由其子类去实现。
package com.example.tcl.myapplication.baselib;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initStatus();
setContentView();
initView();
initData();
}
//对于方法中具体的操作不明确时,使用abstract方法;;
protected abstract void setContentView();
protected abstract void initView();
protected abstract void initData();
//启动Activity
protected void startActivity(Class<?> clazz){
Intent intent = new Intent(this, clazz);
startActivity(intent);
}
//findViewById
public <T extends View>T getViewById(int viewId){
return (T)findViewById(viewId);
}
protected void initStatus(){
// 隐藏标题栏
if (getSupportActionBar() != null)
getSupportActionBar().hide();
// 沉浸效果
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
}
三. 使用
BaseActivity中封装的方法基本上是每个Activity都会使用的方法;如果只是两个或两个以上会使用到的方法(不是普遍用到),通常情况下封装成工具类就行,具体封装的时候一定要根据具体的使用情况选择合适的方式。
public class TestActivity extends BaseActivity {
@Override
protected void setContentView() {
setContentView(R.layout.activity_main);
jumpToMainActivity();
}
/**
* 初始化控件
*/
@Override
protected void initView() {
}
/**
* 初始化数据
*/
@Override
protected void initData() {
}
private void jumpToMainActivity(){
startActivity(MainActivity.class);
}
}
网友评论