java 设计模式-模版方法模式

前言

        Java 中的模板方法模式(Template Method Pattern)是一种行为设计模式,它在父类中定义了一个操作的算法模板,并将某些步骤的执行延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些特定步骤。通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差别适合于这种模式。

一、模版方法模式包含角色

  1. 抽象类(Abstract Class):定义抽象基类,为所有子类提供一个算法框架。

  2. 具体子类(Concrete Classes):根据需要重写父类提供的算法步骤中的某些步骤

二、抽象类中的方法含义

  1. 抽象类:负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成
  2. 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
  3. 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
    • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
    • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
    • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种,一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

三、示例代码

  • 抽象类
package com.demo;

/**
 * 定义抽象类
 * 下班跑路为demo
 * 下班的基本步骤是:1.下班,2.坐车(有班车,公交车),3.到家
 */
public abstract class MyAbstractClass {
    //模板方法(定义基本方法的执行顺序)
    public final void comeHomeFromWork() {
        offDuty();
        car();
        getOff();
    }
    //下面的方法都称为基本方法
    //1.下班
    public void offDuty() {
        System.out.println("到点下班了");
    }
    //2.坐车(有的员工坐班车,有的坐公交车回家,需要子类实现的方法)
    public abstract void car();
    //3.到家了
    public void getOff() {
        System.out.println("到家了");
    }
}
  • 实现类:坐公交车回家
package com.demo;

/**
 * 坐公交车回家
 */
public class Bus  extends MyAbstractClass{
    /**
     * 实现父类的回家方式(坐公交车)
     */
    @Override
    public void car() {
        System.out.println("坐公交车回家");
    }
}
  • 实现类:坐班车回家
package com.demo;
/**
 * 坐班车回家
 */
public class ShuttleBus extends MyAbstractClass{
    /**
     * 实现父类的回家方式(坐班车)
     */
    @Override
    public void car() {
        System.out.println("坐班车回家");
    }
}
  • 测试类
package com.demo;
public class Test {

    public static void main(String[] args) {

        //坐公交车回家
        Bus bus = new Bus();
        bus.comeHomeFromWork();

        System.out.println("=====================================");

        //坐班车回家
        ShuttleBus shuttleBus = new ShuttleBus();
        shuttleBus.comeHomeFromWork();
    }
}
  • 执行结果

四、模板方法模式的扩展

        在上述的案例中,下班回家需要三步(下班,坐车,回家),如果我家就在附近不需要坐车回家,我直接下班就回家,这时就需要引入一个钩子方法来控制执行步骤,跳过不需要的方法调用,也就是说通过钩子方法返回的布尔值来决定是否需要执行模板方法中的某个操作。

        钩子方法 的作用主要体现在以下几个方面:

  • 提供默认行为:钩子方法通常在抽象类中提供了一个默认的实现,这个默认实现可以在模板方法中被调用。如果具体子类选择不覆盖钩子方法,就会使用这个默认行为。这使得在不同的子类中可以有一些通用的行为。
  • 允许选择性的行为扩展:具体子类可以选择性地覆盖钩子方法,以添加或修改某些行为,以适应特定的需求。这为子类提供了一定的灵活性,使其能够自定义模板方法的部分行为,而不需要修改整个模板方法。
  •  控制模板方法执行流程:钩子方法的返回值通常被用于在模板方法中控制流程。例如,可以使用钩子方法返回的布尔值来决定是否执行模板方法中的某个步骤。这样,通过覆盖钩子方法,可以在不同的子类中控制模板方法的执行流程。

五、代码示例

  • 抽象类
package com.demo;

/**
 * 定义抽象类
 * 下班跑路为demo
 * 下班的基本步骤是:1.下班,2.坐车(有班车,公交车),3.到家
 */
public abstract class MyAbstractClass {
    //模板方法(定义基本方法的执行顺序)
    public final void comeHomeFromWork() {
        offDuty();
        if(isCar()){
            car();
        }
        getOff();
    }
    //钩子方法,是否需要坐车(默认返回true:需要坐车)
    public boolean isCar() {
        return true;
    }
    //下面的方法都称为基本方法
    //1.下班
    public void offDuty() {
        System.out.println("到点下班了");
    }
    //2.坐车(有的员工坐班车,有的坐公交车回家,需要子类实现的方法)
    public abstract void car();
    //3.到家了
    public void getOff() {
        System.out.println("到家了");
    }
}
  • 实现类:覆盖钩子函数
package com.demo;

/**
 * 坐公交车回家
 */
public class Bus  extends MyAbstractClass{
    /**
     * 实现父类的回家方式(坐公交车)
     */
    @Override
    public void car() {
        System.out.println("坐公交车回家");
    }

    /**
     * 覆盖钩子函数
     * @return
     */
    @Override
    public boolean isCar(){
        return false;
    }
}
  • 实现类:坐班车回家
package com.demo;
/**
 * 坐班车回家
 */
public class ShuttleBus extends MyAbstractClass{
    /**
     * 实现父类的回家方式(坐班车)
     */
    @Override
    public void car() {
        System.out.println("坐班车回家");
    }
}
  • 测试类
package com.demo;
public class Test {

    public static void main(String[] args) {
        //这个实现类覆盖了钩子函数返回false所以直接点跳过坐车步骤
        Bus bus = new Bus();
        bus.comeHomeFromWork();

        System.out.println("=====================================");

        //坐班车回家
        ShuttleBus shuttleBus = new ShuttleBus();
        shuttleBus.comeHomeFromWork();
    }
}
  • 执行结果

六、模板方法模式优缺点:

优点:

  1. 代码复用:模板方法模式使得算法的某些步骤可以在父类中实现,从而避免了代码的重复。

  2. 行为的扩展性:子类可以通过覆盖钩子方法来扩展或修改算法的行为,而不需要改变算法的结构。

  3. 解耦:模板方法模式将算法的框架与具体实现解耦,使得新增或修改行为对现有代码的影响最小化。

  4. 符合开闭原则:系统对扩展开放,对修改封闭。可以添加新的子类来扩展功能,而无需修改现有代码。

  5. 控制反转:模板方法将算法的控制权反转到父类,使得父类控制整个算法的流程。

  6. 易于维护:由于算法的框架固定,维护和调试变得更加容易。

缺点:

  1. 灵活性降低:模板方法模式的算法框架是固定的,这可能限制了算法的灵活性。

  2. 扩展性受限:如果算法的骨架需要变化,可能需要修改父类,这会影响到所有子类。

  3. 增加系统复杂性:对于简单的算法,使用模板方法模式可能会增加系统的复杂性,因为需要额外定义抽象类和子类。

  4. 钩子方法可能被忽略:如果子类开发者没有意识到需要覆盖钩子方法,可能会导致默认行为被错误地使用。

  5. 难以适应多种变化:如果算法的多个步骤都需要变化,模板方法模式可能需要多个钩子方法,这会使得模板方法过于复杂。

  6. 继承的局限:模板方法模式依赖于继承,这可能限制了其在某些语言或设计中的使用,尤其是那些支持组合优于继承的语言。

        总的来说,模板方法模式是一种强大的设计模式,尤其适用于需要在保持算法结构不变的同时,允许子类提供特定步骤实现的场景。然而,它也需要谨慎使用,以避免过度复杂化系统设计

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值