前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[设计模式] 模板方法模式

[设计模式] 模板方法模式

作者头像
呼延十
发布2019-06-26 16:49:08
3190
发布2019-06-26 16:49:08
举报
文章被收录于专栏:呼延呼延

前言

在上一篇文章责任链模式中提到了模板方法模式,因此这里简单介绍一下.

模板方法模式比较简单,或者说比较常用.在开发过程中,许多人在不知不觉的情况下就会使用,只要他具有良好的面对对象思维.

比如当你写了DogCat两个类,发现很多相同的代码,你自然就会将相同模块提取抽象成父类,然后将一些公共的方法放到父类中,这样子就基本实现了模板方式模式.

介绍(摘自《Head FIrst 设计模式》)

在一个方法中定义一个算法的骨架,而将一些详细的步骤延迟到子类中.

模板方法使得子类可以在不改变算法结果的基础上,重新定义算法中的某些步骤.

类图

2019-03-19-23-58-35
2019-03-19-23-58-35

角色

抽象模板: 抽象模板一般有一个具体实现的方法,用来定义算法的基础骨架.还有一些抽象方法留给子类去具体实现.此外还有一些有默认实现的钩子方法.子类可选实现.

具体模板: 继承父类的具体方法,实现他们的抽象方法,对于钩子方法,可以根据自身情况决定是都重写.

举个栗子

书上的例子好多了,网络上也有很多,我自己临时瞎想一个吧,不保证一定合适.

假如我们现在要实现两个类,DogCat,并且实现他们的进攻方法.

我们大致实现以下,如下.

Cat:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public class Cat1 {

  private void attack() {

    prepared();
    jump();
    bite();

  }

  private void prepared() {

  }

  private void jump() {

  }

  private void bite() {

  }

}

Dog:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public class Dog1 {

  private void attack(){

    prepared();
    run();
    shout();
    bite();

  }

  private void prepared(){

  }

  private  void run(){

  }

  private void shout(){

  }

  private void bite(){

  }
}

仔细查看代码,发现其实他们的攻击过程很相似.

狗:准备,跑过去,发出声音,咬住 猫:准备,跳过去,咬住

但是这样子编码的话,我们将相同的preparedbite分别写了两次,这是不科学的.

很明显我们可以实现一个父类,将preparedbite在父类里实现他们分别继承就好了.

那么对于shoutjump/run方法呢?就分别实现了嘛?

不是的,jumprun都是移动,只是实现方法不同,也是可以抽象到父类的,那么shout呢?这就是钩子的作用了,可以动态控制当前动物是否会发出声音之后再进行攻击.

改进后的代码如下:

首先是动物模板类:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public abstract class AnimalTemplate {

  protected boolean isShout;

  public final void attack() {
    //
    prepared();
    move();
    if (isShout) {
      shout();
    }
    bite();

  }

  private void prepared() {
    //具体实现准备方案
    System.out.println("准备");
  }

  abstract void move();

  private void bite() {
    //具体实现咬的方式
    System.out.println("咬");
  }

  abstract void shout();

  public void setShout() {
    isShout = true;
  }
}

注意,代码中的setShout是钩子方法,这里简单的用一个变量来当做钩子,此外,preparedbite是具体方法,而moveshout为抽象方法.

下面是狗的具体实现:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public class Dog extends AnimalTemplate {

  @Override
  void move() {
    System.out.println("我是狗,我跑过去");
  }

  @Override
  void shout() {
    System.out.println("我是狗,我叫一下,吓唬吓唬他");
  }
}

猫的具体实现:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public class Cat extends AnimalTemplate {

  @Override
  void move() {
    System.out.println("我是猫,我跳过去.");
  }

  @Override
  void shout() {
    System.out.println("我是猫,我不叫.");
  }

  @Override
  public void setShout() {
    this.isShout = false;
  }
}

测试类:

代码语言:javascript
复制
package design_patterns.template_pattern;

/**
 * created by huyanshi on 2019/3/20
 */
public class Test {

  public static void main(String[] args) {

    AnimalTemplate dog = new Dog();
    dog.setShout();
    dog.attack();

    AnimalTemplate cat = new Cat();
    cat.setShout();
    cat.attack();
  }
}

输出结果:

代码语言:javascript
复制
准备
我是狗,我跑过去
我是狗,我叫一下,吓唬吓唬他
咬
准备
我是猫,我跳过去.
咬

对比上下的代码可以发现,在第二个版本中,没有一些重复的代码,且子类的逻辑更加清晰,仅仅实现了自己与其他类不相同的部分,或者自己想要实现的部分钩子方法.

而且当动物越来越多,代码的总量会越来越少且容易维护,新添加一个动物,只需要继承动物模板,然后实现moveshout即可.

总结

首先注意一下:在模板方法的attack上,添加了final关键字,可以防止该方法被重写,可以保证attack这一方法,在定义及流程上的正确性及安全性,而具体的实现可以交给子类.

模板方法的优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。

缺点:

类的个数较多.

完。

ChangeLog

2019-03-20 完成

以上皆为个人所思所得,如有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文链接。

联系邮箱:huyanshi2580@gmail.com

更多学习笔记见个人博客——>呼延十

var gitment = new Gitment({ id: '[设计模式] 模板方法模式', // 可选。默认为 location.href owner: 'hublanker', repo: 'blog', oauth: { client_id: '2297651c181f632a31db', client_secret: 'a62f60d8da404586acc965a2ba6a6da9f053703b', }, }) gitment.render('container')



本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 介绍(摘自《Head FIrst 设计模式》)
  • 类图
  • 角色
  • 举个栗子
  • 总结
    • ChangeLog
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档