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

【设计模式】模板方法设计模式

作者头像
Li_XiaoJin
发布2022-06-10 18:21:42
5980
发布2022-06-10 18:21:42
举报
文章被收录于专栏:Lixj's BlogLixj's Blog

定义

模板方法设计模式的定义如下: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

实践

定义一个起床模型

代码语言:javascript
复制
public abstract class CarModel {

    // 车子启动
    public abstract void start();
    // 车子停止
    public abstract void stop();
    // 车子鸣笛
    public abstract void alerm();
    // 车子引擎轰鸣
    public abstract void engineBoom();
    // 行驶
    final public void run() {
        // 启动汽车
        this.start();
        // 引擎轰鸣
        this.engineBoom();
        // 喇叭鸣笛
        this.alerm();
        // 停止
        this.stop();
    }

}

A类汽车:

代码语言:javascript
复制
public class ACar extends CarModel {
    @Override
    public void start() {
        System.out.println("ACar启动。。。。");
    }

    @Override
    public void stop() {
        System.out.println("ACara停止。。。。");
    }

    @Override
    public void alerm() {
        System.out.println("ACar鸣笛。。。1111");
    }

    @Override
    public void engineBoom() {
        System.out.println("ACar引擎轰鸣。。。1111");
    }

}

B类汽车:

代码语言:javascript
复制
public class BCar extends CarModel {
    @Override
    public void start() {
        System.out.println("BCar启动。。。。");
    }

    @Override
    public void stop() {
        System.out.println("BCara停止。。。。");
    }

    @Override
    public void alerm() {
        System.out.println("BCar鸣笛。。。1111");
    }

    @Override
    public void engineBoom() {
        System.out.println("BCar引擎轰鸣。。。1111");
    }

}
代码语言:javascript
复制
public class Client {
    public static void main(String[] args) {
        CarModel car = new ACar();
        car.run();

        CarModel bCar = new BCar();
        bCar.run();
    }
}

模板如下:

代码语言:javascript
复制
public abstract class AbtractClass {
    // 基本方法
    public abstract void doSomething1();
    // 基本方法
    public abstract void doSomething2();
    // 模板方法
    public void templateMethod() {
        this.doSomething1();
        this.doSomething2();
    }

}


public class ConcreteClass1 extends AbtractClass {
    @Override
    public void doSomething1() {
        // 具体实现
    }

    @Override
    public void doSomething2() {
        // 具体实现
    }
}


public class ConcreteClass2 extends AbtractClass {
    @Override
    public void doSomething1() {
        // 具体实现
    }

    @Override
    public void doSomething2() {
        // 具体实现
    }
}

钩子方法:

不是由该方法的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 如果某个子类需要在ConcreteMethod方法后,在AbstractMethod方法前进行某些操作,就可以覆盖这个钩子方法,实现自己的逻辑即可,并不需要修改父类或其调用方。钩子就是在整体流程的设计中,故意留下的供子类灵活变更的钥匙。 钩子是一种被声明在抽象类中的方法,但钩子只有空的或者默认方法实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩由子类自行决定。 当在模板方法中某一些步骤是可选的时候,也就是该步骤不一定要执行,可以由子类来决定是否要执行,则此时就需要用上钩子。钩子是一种被声明在抽象类中的方法,但一般来说它只是空的或者具有默认值,子类可以实现覆盖该钩子,来设置算法步骤的某一步骤是否要执行。钩子可以让子类实现算法中可选的部分,让子类能够有机会对模板方法中某些一即将发生的步骤做出反应。

代码语言:javascript
复制
public abstract class NewCarModel {

    // 车子启动
    public abstract void start();
    // 车子停止
    public abstract void stop();
    // 车子鸣笛
    public abstract void alerm();
    // 车子引擎轰鸣
    public abstract void engineBoom();
    // 行驶
    final public void run() {
        // 启动汽车
        this.start();
        // 引擎轰鸣
        this.engineBoom();
        // 喇叭鸣笛
        if (this.isAlarm()) {
            this.alerm();
        }
        // 停止
        this.stop();
    }

    public boolean isAlarm() {
        return true;
    }

    public void setAlarm(boolean alarm) {
        ;
    }
}

public class NewACar extends NewCarModel {
    //
    private boolean alarmFlag = true;

    @Override
    public void start() {
        System.out.println("ACar启动。。。。");
    }

    @Override
    public void stop() {
        System.out.println("ACara停止。。。。");
    }

    @Override
    public void alerm() {
        System.out.println("ACar鸣笛。。。1111");
    }

    @Override
    public void engineBoom() {
        System.out.println("ACar引擎轰鸣。。。1111");
    }

    public boolean isAlarm() {
        return this.alarmFlag;
    }

    public void setAlarm(boolean isAlarm) {
        this.alarmFlag = isAlarm;
    }

}


public class NewBCar extends NewCarModel {

    @Override
    public void start() {
        System.out.println("BCar启动。。。。");
    }

    @Override
    public void stop() {
        System.out.println("BCara停止。。。。");
    }

    @Override
    public void alerm() {
        System.out.println("BCar鸣笛。。。1111");
    }

    @Override
    public void engineBoom() {
        System.out.println("BCar引擎轰鸣。。。1111");
    }

    public boolean isAlarm() {
        // 默认不鸣笛
        return false;
    }

}


public class Client1 {
    public static void main(String[] args) {
        NewACar car = new NewACar();
        car.setAlarm(true);
        car.run();

        NewBCar bCar = new NewBCar();
        bCar.run();
    }
}

总结

模板模式的业务场景可能在平时的开发中不是很常见,主要因为这种设计模式会在抽象类中定义逻辑行为的执行顺序。一般情况下,使用抽象类定义的逻辑行为会比较轻量级或者没有逻辑行为,只提供一些基本方法,供公共调用和实现。但如果遇到适合的场景,使用这种设计模式也非常方便,因为可以控制整套逻辑的执行顺序和统一的输入、输出,而对于实现方,只需要关心自己的业务逻辑即可。

另外,模板模式也是为了解决子类通用方法,放到父类中优化设计。让每一个子类只做子类需要完成的内容,而不需要关心其他逻辑。再提取公用代码,行为由父类管理,扩展可变部分,也就非常有利于开发拓展和迭代了。

优点:

  1. 封装不变部分,扩展可变部分。
  2. 提取公共代码,便于维护。
  3. 行为由父类控制,子类实现。

缺点:

  • 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景:

  1. 有多个子类共有的方法,且逻辑相同。
  2. 重要的、复杂的方法,可以考虑作为模板方法。

注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/设计模式-模板方法设计模式

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 实践
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档