Android 最常用的设计模式四 安卓源码分析——模板方法(Mould)



  1. 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。即:一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。

  2. 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

  3. 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。


  • 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。

  • 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

    抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在Java语言里抽象方法以abstract关键字标示。

    模板方法 一 个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。


实例: 在Android中,往往会有一些全局的基类,包括BaseActivity,BaseFragment等等,
用于规范整个程序的View层的代码风格,此时,即可充分运用到模板方法模式
public abstract class IBaseActivity extends Activity{

    /**
     * 模板方法,用于返回布局ID
     */
    public abstract int initLayout();

    /**
     * 模板方法,初始化View
     * final方法必须有执行体
     * 和抽象方法是有区别
     */
    public final void initView(){
        setColor();
    };

    public void setColor(){

    }

    /**
     * 模板方法,获取数据,执行耗时操作
     */
    protected abstract void requestData();

    /**
     * 提供给子类动态设置状态栏颜色
     */
    protected void setSystemBarColor(int colorId) {

    }

    //...省略一体化状态栏处理

    /**
     * 该方法在onCreate中执行,用于获取Fragment的参数传递
     * 子类可按情况自行选择复写
     */
    protected void getArgs() {

    }
public class MainActivity extends IBaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public int initLayout() {
        return 0;
    }

    @Override
    protected void requestData() {

    }
}
总结:
一个抽象类,一个实现类,抽象类里面放一个final的方法.
  • 父类中控制流程的方法定义为Final
  • 父类中提供一系列子类可复写的方法,从而将具体步骤中的实现延迟到子类中

从上面可以看出,BaseActivity中的Oncrea()方法被定义为Final,所以子类是无法重写的,这样可以很好的避免子类复写导致执行流程被打乱.由于父类中流程已经定义好,子类只需要负责具体实现的步骤即可,这样代码结构非常清晰,且不容易出错.


安卓代码中用到的地方:

1.View的绘制

2.AsyncTask

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

@MainThread
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;
}

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。

相当于继承一样!,父类调用子类去干什么事情

打比方说父亲有很多理想,就行医救人吧,但是父亲医术不行,只能靠儿子,儿子长大后遵从父亲大志,春风拂面,妙手回春,实现了父亲的理想,儿子做的事情早在出生前就定下来了,是父亲之前久定好的模板。
认识到模板方法的这种思想,父类可以让未知的子类去做它本身可能完成的不好或者根本完成不了的事情,对框架学习大有帮助。

别调用我们,我会调用你
(就好比猎头和求职者,求职者不需要去找猎头,猎头只要有工作就会找到你)称之为好莱坞原则



  1. 对一些复杂的算法进行分割,将其算法中固定不变的部分设计为模板方法和父类具体方法,而一些可以改变的细节由其子类来实现。即:一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。

  2. 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

  3. 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。


  • 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。

  • 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

    抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在Java语言里抽象方法以abstract关键字标示。

    模板方法 一 个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。


实例: 在Android中,往往会有一些全局的基类,包括BaseActivity,BaseFragment等等,
用于规范整个程序的View层的代码风格,此时,即可充分运用到模板方法模式
public abstract class IBaseActivity extends Activity{

    /**
     * 模板方法,用于返回布局ID
     */
    public abstract int initLayout();

    /**
     * 模板方法,初始化View
     * final方法必须有执行体
     * 和抽象方法是有区别
     */
    public final void initView(){
        setColor();
    };

    public void setColor(){

    }

    /**
     * 模板方法,获取数据,执行耗时操作
     */
    protected abstract void requestData();

    /**
     * 提供给子类动态设置状态栏颜色
     */
    protected void setSystemBarColor(int colorId) {

    }

    //...省略一体化状态栏处理

    /**
     * 该方法在onCreate中执行,用于获取Fragment的参数传递
     * 子类可按情况自行选择复写
     */
    protected void getArgs() {

    }
public class MainActivity extends IBaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public int initLayout() {
        return 0;
    }

    @Override
    protected void requestData() {

    }
}
总结:
一个抽象类,一个实现类,抽象类里面放一个final的方法.
  • 父类中控制流程的方法定义为Final
  • 父类中提供一系列子类可复写的方法,从而将具体步骤中的实现延迟到子类中

从上面可以看出,BaseActivity中的Oncrea()方法被定义为Final,所以子类是无法重写的,这样可以很好的避免子类复写导致执行流程被打乱.由于父类中流程已经定义好,子类只需要负责具体实现的步骤即可,这样代码结构非常清晰,且不容易出错.


安卓代码中用到的地方:

1.View的绘制

2.AsyncTask

public abstract class AsyncTask<Params, Progress, Result> {
    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // We want at least 2 threads and at most 4 threads in the core pool,
    // preferring to have 1 less than the CPU count to avoid saturating
    // the CPU with background work
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

@MainThread
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;
}

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。

相当于继承一样!,父类调用子类去干什么事情

打比方说父亲有很多理想,就行医救人吧,但是父亲医术不行,只能靠儿子,儿子长大后遵从父亲大志,春风拂面,妙手回春,实现了父亲的理想,儿子做的事情早在出生前就定下来了,是父亲之前久定好的模板。
认识到模板方法的这种思想,父类可以让未知的子类去做它本身可能完成的不好或者根本完成不了的事情,对框架学习大有帮助。

别调用我们,我会调用你
(就好比猎头和求职者,求职者不需要去找猎头,猎头只要有工作就会找到你)称之为好莱坞原则





猜你喜欢

转载自blog.csdn.net/WHB20081815/article/details/77984746