美文网首页
设计模式--模板模式

设计模式--模板模式

作者: Qi0907 | 来源:发表于2018-11-08 15:25 被阅读0次

一、举个栗子


image.png

用Java实现一下吧

//煮咖啡                                  //泡茶
public class Coffee {                    public class Tea {
  void prepareRecipe() {                   void prepareRecipe() {
    boilWater();                              boilWater();
    brewCoffeeGrinds();                       steepTeaBag();
    pourInCup();                              pourInCup();
    addSugarAndMilk();                        addLemon();
  }                                         }
  //每个操作步骤的具体实现                    //每个操作步骤的具体实现
  public void boilWater() {                 public void boilWater() {
    ....                                      ....
  }                                         }
  public void brewCoffeeGrinds() {          public void steepTeaBag() {
      ....                                    ....
  }                                         }
  public void pourInCup() {                 public void pourInCup() {
    ....                                      ....
  }                                         }
  public void addSugarAndMilk() {           public void addLemon() {
    ....                                      ....
  }                                         }
}                                         }

可以看出有很多重复的代码,那么直接把重复的代码抽取出来
1.版本1.0


image.png

2.版本2.0
再仔细看看,还是有重复的方法


image.png

浸泡(steep)和冲泡(brew)差异其实并不大,就都叫brew(),而加糖,牛奶和柠檬也很相似,都是加入调料,都叫addCondiments()好了。
有了新的prepareRecipe(),就可以设计咖啡因饮料(CaffeineBeverage)的超类了
A.设计超类

public abstract class CaffeineBeverage{
    //声明为final,保证子类不会覆盖他
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }
    //下面这两个类必须是抽象的,因为咖啡和茶的处理方式不同
    abstract void brew();
    abstract void addCondiments();
    //下面这两个类是共同的,放到超类里实现
    public void boilWater() {
        ....
    }
    public void pourInCup() {
        ....
    }
}

B.咖啡类的实现

public class Coffee extends CaffeineBeverage {
    public void brew() {
        ...
    }
    public void addCondiments() {
        ...
    }
}
```
C.茶类的实现
```
public class Tea extends CaffeineBeverage {
    public void brew() {
        ...
    }
    public void addCondiments() {
        ...
    }
}

主要思想


image.png

二、模板方法

  1. 定义
    模板方法:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
    冲泡咖啡和茶的例子就是一个模板方法


    image.png

通过这个例子可以看出,由CaffineBeverage类主导一切,拥有算法,并通过final保护这个算法,而不是Coffee或Tea各自有各自的算法,并且可以使代码进行复用,所有的算法只存在于CaffineBeverage类中,修改也容易,不必修改多个类,如果新加入其它咖啡因的饮料也非常容易。
2、类图


image.png

3、分析抽象类

//这个抽象类作为基类,其子类必须实现其操作
abstract class AbstractClass {
    //声明为final,以免子类改变这个算法的顺序
    final void templatemethod() {
        //定义了一连串的步骤,每个步骤由一个方法代表
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        hook();
    }
    //下面的抽象方法子类必须实现
    abstract void primitiveOperation1();
    abstract void primitiveOperation2();
    //声明为final,使得子类无法覆盖它,它可以被模板方法直接使用,或被子类使用
    final void concreteOperation() {
        ...
    }
    //可以有“默认不做的方法”,这个方法为“hook”,子类可视情况决定是否覆盖
    void hook() {}
}

4、hook()
hook()是一种被声明在抽象类中的方法,但只有空的或默认的实现,hook()的存在,可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类决定
举例:

public abstract class CaffeineBeverageWithHook {
    final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        //加上一个条件,如果顾客“想要”调料,才加入
        if (customerWantsCondiments()) {
            addCondiments();
        }
    }
    abstract void brew();
    abstract void addCondiments();
    public void boilWater() {
        ....
    }
    public void pourInCup() {
        ....
    }
    //定义一个方法,通常是空的缺省实现,只会返回true
    boolean customerWantsCondiments() {
        //子类可以覆盖
        return true;
    }
}

使用hook

public class CoffeeWithHook extends CaffeineBeverageWithHook {
    public void brew() {
         ...
    }
    public void addCondiments() {
        ...
    }
    //子类覆盖了这个hook,提供了自己的功能
    public boolean customerWantsCondiments(String answer) {
        //让用户输入他们对调料的决定,根据用户的输入返回true或false
        String answer = answer;
        if (answer.equals(“Yes”)) {
            return true;
        } else {
            return false;
        }
    }
}

当子类“必须”提供算法中某个方法或步骤实现时,就使用抽象方法,如果算法的某个部分是可选的,就用hook,这样子类可以去选择是否实现它。hook的一个用法是像上面的例子,使抽象类中的某些方法是可选的,另一种方法是让子类能够有机会对模板方法中某些即将发生(或刚刚发生的)步骤做出反应,例如,允许子类在得到数据后执行某些动作(显示数据等)。
5、好莱坞原则
别调用我们,我们会调用你--允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。


image.png

三、模板方法在Android中的应用
1、Activity、Fragment
Activity、Fragment等有自己固定的生命周期,它按照Android自己设计的状态进行流转,但是在那个状态需要做什么事情,是与具体的应用有关。因此Activity、Fragment就定义了许多hook方法,如onStart(),onResume(),onStop()等,应用要想处理自己的业务,就继承Activity或者Fragment,并重写这些方法就可以了。
2、View

public class View{ 
    //钩子方法,空实现 
    protected void onDraw(Canvas canvas) { 
    } 
    //钩子方法,空实现 
    protected void dispatchDraw(Canvas canvas) { 
    } 
    //绘制方法,定义绘制流程 
    public void draw(Canvas canvas) {
    }
}

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

private AsyncTask task = new AsyncTask() {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override
    protected Object doInBackGround(Object[] params) {
        return null;
    }
    @Override
    protected void onPostExecute(Object o) {
        super.onPostExecute(o);
    }
}

相关文章

网友评论

      本文标题:设计模式--模板模式

      本文链接:https://www.haomeiwen.com/subject/iliixqtx.html