设计模式--模板模式

一、举个栗子


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);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.模板模式的定义及使用场景定义一个操作中的算法框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即...
    GB_speak阅读 742评论 0 0
  • 最近在写的采集框架,为了实现功能扩展,采用了大量的配置文件。这就造成了每添加一个站点都需要手动配置大量参数。对这种...
    涅槃1992阅读 600评论 0 4
  • 概念与定义 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子...
    maxwellyue阅读 385评论 0 0
  • DAY57伯德小姐 真是今年以来最棒的青春片为什么是说它棒而不是说好看因为觉得比好看的电影更↑的一部好电影 在微博...
    冯双喜_Hugo阅读 155评论 0 0
  • 剑客轻轻一跳,越过三丈高的围墙,稳稳地落在大宅的院子。现在是正午时分,院子里却出奇的安静,宽敞的地方空无一人,...
    lk洛阅读 1,191评论 0 5