设计模式--模板模式

一、举个栗子


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);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

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