设计模式之模板方法模式(Template Method)

介绍

什么是模板?
模板的原意是指,通过使用既定的工具、模具来不断的生产相似的产品。如,有镂空文字的塑料模板,我们只需要用笔在模板的镂空文字处临摹,便可写出整齐的文字。不管使用什么样的笔,签字笔,彩笔、铅笔,文字的形状都会与镂空处的形状一致。

什么是Template Method 模式?
顾名思义,其实就是带有模板功能的模式,组成模板的方法被定义在父类中。由于这些方法是抽象方法,不能知道他们是怎么实现的,所以只是查看父类的代码不能知道这些方法最终会做怎样的处理,唯一能知道的就是父类怎么调用这些方法的(父类自身实现的方法)。

而实现父类所定义的抽象方法的则是子类。子类实现了抽象方法就决定了具体的处理,不同的子类实现不同的具体处理,当父类的模板方法被调用时程序的行为也会不同。不管子类的具体实现如何,处理的流程都会按照父类所定义的方式去执行(即父类自身实现的方法定义了怎么去使用抽象方法,子类实现抽象方法的具体实现不同,则结果就会不同)

像这样,父类中定义具体处理流程的框架,子类中实现具体处理行为的模式就成为Template Method模式

类图:
在这里插入图片描述

示例程序

我们现在做一个小的程序来展现我们了解的模板方法模式。这个实例程序是将字符和字符串打印5次的程序

示例程序类图:
在这里插入图片描述

AbstractDisplay 类是一个抽象类,分别由一下4个方法,其中open、print、close是抽象方法,具体的实现将交给AbstractDisplay 的子类,display方法是将字符串按照规则打印出来。
规则如下:
调用open方法。
循环调用5次print方法
调用close方法

public abstract class AbstractDisplay {

    public abstract void close();

    public abstract void open();

    public abstract void print();

    public void display() {
        open();
        for (int i = 0; i<5; i++){
            print();
        }
        close();
    };
}

CharDisplay 类继承于AbstractDisplay 类,并且对AbstractDisplay 类所有的抽象方法做出了具体的实现。

方法名处理
open显示字符串“<<”
close显示字符串“>>”
print显示构造方法传入的字符

当我们调用display方法时,假设我们向CharDisplay类构造函数中传入了一个 ‘H’ 的字符,那么显示的字符串应是:

<<HHHHH>>
public class CharDisplay extends AbstractDisplay {

    private char ch;

    CharDisplay(char ch){
        this.ch = ch;
    }

    public void close() {
        System.out.println(">>");
    }

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

    public void print() {
        System.out.print(ch);
    }
}

StringDisplay 类同样继承于AbstractDisplay,并针对AbstractDisplay类抽象方法做出了不同于CharDisplay 类的具体实现。StringDisplay在创建时需要向构造方法传入一个字符串,并且将这个字符串的字节长度及字符串分别赋予StringDisplay类的两个成员变量,printLine方法是打印上下两条边框的一个方法,供close、open方法进行调用。最终的结果是希望得到一个将字符串包裹的一个边框。

假设我们向StringDisplay 类传入了一个“Hello World。”最终的结果会如此:

+------------+
|Hello World.|
|Hello World.|
|Hello World.|
|Hello World.|
|Hello World.|
+------------+
方法名处理
open显示字符串“±-----------+”
close显示字符串“±-----------+”
print显示构造方法,并用“
public class StringDisplay extends AbstractDisplay {

    private String str;     //需要显示的字符串
    private int length;     //记录传入的字符串的字节长度

    StringDisplay(String str){
        this.str = str;
        this.length = str.getBytes().length;
    }

    public void close() {
        printLine();
    }

    public void open() {
        printLine();

    }

    public void print() {
        System.out.println("|" + str + "|");    //将字符串打印出来
    }

    private void printLine(){
        System.out.print("+");                  //显示边框的角
        for (int i= 0; i<length; i++){
            System.out.print("-");              //显示的边框
        }
        System.out.println("+");                //显示边框的角
    }
}

模板方法模式的优点
1、使处理的逻辑通用化,将具体的处理抽象交由子类去实现,具体的使用流程则有父类实现。一套接口,多种实现。
2、使检查和维护变得简单方便,因为具体的使用是由父类进行的,当我们在模板方法中发现bug时,只需要修模板方法中的代码就可解决问题
3、父类和子类拥有一致性,使用父类的类型变量保存子类的示例,无论父类变量中保存的是哪个子类的实例程序都可以正常的运行

模板方法中出现的角色
1、抽象类(AbstractClass):AbstractClass角色不仅负责实现模板方法,还负责声明在模板方法中所使用到的抽象方法。这些抽象方法由子类(ConcreteClass)角色负责实现。
2、具体类(ConcreteClass):该角色负责实现AbstractClass类中定义的抽象方法,这里实现的方法将会在AbstractClass角色的模板方法中被调用

拓展与延伸
以类的层次去理解时,通常是站在子类的角度去思考。即:很容易想到以下的几点:

  • 子类中可以使用父类定义的方法
  • 子类可以添加新的方法实现新的功能
  • 子类可以重写父类的方法改变程序的行为

而站在父类的角度去思考,在父类中,我们声明了抽象方法且将该方法交由子类去实现。换而言之,就程序而言,声明抽象方法是希望达到以下的目的:

  • 期待子类去实现抽象方法
  • 要求子类去实现抽象方法

即:子类具有实现父类中所声明的抽象方法的责任。而这种责任被称为“子类责任”。

父子类的协作:在模板方法(Template Method)模式中,父类和子类是紧密联系的,他们共同支撑起了整个程序。因此在子类实现抽象方法时,必须要理解抽象方法被调用的时机。在看不到父类源代码的情况下想要编写出子类是非常困难的。
虽然**将更多的方法的实现放在父类能有效的减少子类的负担,但同样也降低了程序的灵活性。反之,如果父类中实现的方法过少,也会让子类变得臃肿不堪。**所以,“如何划分处理级别,哪些有子类实现,哪些由父类实现”并没有具体的定式,都需要有程序设计的开发人员根据具体情况决定

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值