设计模式——模板设计模式(Template Method)

模板设计-base

什么是模板?

举个简单的例子,以AABB的格式,写出一个词语,你可能会想到,明明白白,干干净净等,
这个AABB就是一个模板,对模板心中有了一个清晰的概念之后,我们再来看今天我们的内容,模板设计。

实现思路

我们在父类中,定义处理流程的框架,子类中实现具体处理

要如何实现这样的思路呢?

在父类中定义多个抽象方法,然后由一个模板方法来进行调用,决定如何使用这些模板方法,就形成了处理流程的框架。

子类继承父类,只需要实现抽象方法。这样一来模板方法就留在了父类中,各个子类都可以有自己的实现方式。

代码实现

在这里插入图片描述

在这里插入图片描述

我们定义AbstractDisplay作为父类里面有open、print、close 3个抽象方法,一个display模板方法

charDisplay和StringDisplay作为AbstractDisplay的子类,去实现各自的open、print、close方法。
最终我们用子类统一去调用父类已经实现的display模板方法,查看效果。

public abstract class AbstractDisplay {
    /**
     * 交给字类实现的抽象方法(1) open
     */
    public abstract void open();
    /**
     * 交给字类实现的抽象方法(2)print
     */
    public abstract void print();
    /**
     * 交给字类实现的抽象方法(3)close
     */
    public abstract void close();

    /**
     * 模板方法,先调用open在调用5次print方法,最后调用close。
     * 可以看出,父类中只调用抽象方法,但不实现抽象方法,具体实现交给子类。
     */
    public final void display(){
        open();
        for (int i = 0; i < 5; i++) {
            print();
        }
        close();
    }
}

接下来让我们看看CharDisplayStringDisplay是如何实现的。

public class CharDisplay extends AbstractDisplay{
    private char character;

    public CharDisplay(char c){
        this.character = c;
    }

    @Override
    public void open() {
        System.out.print("<<");
    }

    @Override
    public void print() {
        System.out.print(character);
    }

    @Override
    public void close() {
        System.out.println(">>");
    }
}
public class StringDisplay extends AbstractDisplay{

    private String string;
    private Integer times;

    public StringDisplay(String string) {
        this.string = string;
        times = string.toCharArray().length;
    }



    @Override
    public void open() {
        System.out.print("+");
        for (int i = 0; i < times; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }

    @Override
    public void print() {
        System.out.println("|"+string+"|");
    }

    @Override
    public void close() {
        System.out.print("+");
        for (int i = 0; i < times; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }
}

让我们在Main类中调用试试看吧

public class Main3 {
    public static void main(String[] args) {
        //生成一个持有'H'的CharDisplay实例
        AbstractDisplay d1 = new CharDisplay('H');
        //生成一个持有'Hello,world.'的StringDisplay类的实例
        AbstractDisplay d2 = new StringDisplay("Hello,world.");
        //由于d1、d2都是AbstractDisplay的实例,可以调用继承的display方法,实际的程序行为取决于CharDisplay类和StringDisplay类的具体实现
        d1.display();
        d2.display();
    }
}

输出结果
在这里插入图片描述
我们创建了一个AbstractDisplay的模板,最终却生成了两种不同的结果!就像AABB的模板最终可以生成明明白白和干干净净一样!

恭喜你!!掌握了模板设计模式的基本使用!接下来让我们拓展一下思路。

思路拓展

可以使逻辑处理通用化

使用 Template Method模式究竟能带来什么好处呢?

让我们先看看Template Method模式的类图是什么样的
在这里插入图片描述

使用 Template Method模式究竟能带来什么好处呢?

这里,它的优点是由于在父类的模板方法中编写了算法,因此无需在每个子类中再重复编写算法。

例如,我们没使用 Template Method模式,而是使用文本编辑器的复制和粘贴功能编写了多个ConcreteClass角色。此时,会出现ConcreteClass1、ConcreteClass2、Concreteclass3 等很多相似的类。编写完成后立即发现了Bug还好,但如果是过一段时间才发现在Concreteclass1中有 Bug,该怎么办呢?这时,我们就必须将这个 Bug的修改反映到所有的 ConcreteClass 角色中才行。

关于这一点,如果是使用 Template Method模式进行编程,当我们在模板方法中发现Bug时只需要修改模板方法即可解决问题

父类与子类之间的协助

在 Template Method模式中,父类和子类是紧密联系、共同工作的。因此,在子类中实现父类中声明的抽象方法时,必须要理解这些抽象方法被调用的时机。在看不到父类的源代码的情况下想要编写出子类是非常困难的。

模板设计-plus

练习题一

java.io.Inputstream类使用了Template Method模式。请阅读官方文档(JDK的API参考资料 ),从中找出需要用java.io.Inputstream 的子类去实现的方法。

练习题二

上面给出的AbstractDisplay类的display方法如下

public final void display(){
	....
}
这里使用了final修饰符,请问这是想表达什么意思呢?

练习题三

如果想要让示例程序中的open、print、close方法可以被具有继承关系的类和同一程序包中的类调用,但是不能被无关的其他类调用,应当怎么做呢?

练习题四

Java中的接口与抽象类很相似。接口同样也是抽象方法的集合,但是在TemplateMethod 模式中,我们却无法使用接口来扮演AbstractClass角色,请问这是为什么呢?

答案

练习题一

查阅文档后,你就会知道,InputStream是一个抽象类,其中需要子类实现的抽象方法只有一个就是read方法啦!
在这里插入图片描述

在这里插入图片描述

练习题二

final关键字修饰方法的时候,表示定义在父类中的模板方法display无法在子类中进行重写,这正和我们期望的一致,我们希望模板方法由父类直接实现,即父类直接定义抽象方法的使用框架,不希望子类再去进行重写,使用模板设计模式时,子类也不应该重写模板方法。

练习题三

可以将AbstractDisplay类中的open,print,close方法的可见性声明为protected。这样就可以让继承该类的子类调用这些方法,而其他包中的类无法调用这些方法(不过同一个包中的类依然可以调用这些方法)。

练习题四

这是因为 TemplateMethod模式中的AbstractClass角色必须实现处理的流程。在抽象类中可以实现一部分方法(例如 AbstractDisplay类中的display方法),但是在接口中是无法实现方法的。因此,在TemplateMethod 模式中,无法用接口替代抽象类。

在Java8之前以上结论成立,在Java8之后,引入了defualt关键字,增强了接口的功能,使得接口也可以实现方法。

知识关联性

Factory Method 模式(工厂模式)

是将 Template Method 模式用于生成实例的一个典型例子。

Strategy模式(策略模式)

在 Template Method 模式中,可以使用继承改变程序的行为。这是因为 Template Method 模式在父类中定义程序行为的框架,在子类中决定具体的处理。
与此相对的是 Strategy模式,它可以使用委托改变程序的行为。与Template Method 模式中改变部分程序行为不同的是,Strategy模式用于替换整个算法。

模板设计模式(Template Method)的讲解到此就结束啦,感谢阅读。💕

  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的模板设计模式是一种行为型设计模式,它允许我们定义一个算法的骨架,但允许子类为其中的一些步骤提供具体的实现。 模板设计模式由两个主要组件组成: 1. 抽象类(Abstract Class):它定义了一个模板方法,该方法提供了算法的骨架。它可以包含一个或多个抽象方法,这些方法由子类来实现。 2. 具体类(Concrete Class):它是抽象类的子类,负责实现抽象方法。 以下是一个示例代码来说明模板设计模式的用法: ```java public abstract class AbstractClass { // 模板方法 public final void templateMethod() { // 步骤一 stepOne(); // 步骤二 stepTwo(); // 步骤三 stepThree(); } // 抽象方法,由子类实现 protected abstract void stepOne(); protected abstract void stepTwo(); // 钩子方法,子类可以选择性地覆盖 protected void stepThree() { // 默认实现 } } public class ConcreteClass extends AbstractClass { @Override protected void stepOne() { // 具体实现步骤一 } @Override protected void stepTwo() { // 具体实现步骤二 } } ``` 在上面的示例中,`AbstractClass` 是抽象类,它定义了一个名为 `templateMethod()` 的模板方法,并声明了三个抽象方法 `stepOne()`、`stepTwo()` 和 `stepThree()`。`ConcreteClass` 是具体类,它继承了 `AbstractClass` 并实现了抽象方法。 通过使用模板设计模式,我们可以在抽象类中定义算法的骨架,而具体的实现可以由子类来完成。这种设计模式使得代码重用和扩展变得更加容易。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值