Template Method——模板方法模式

模板方法模式是一种设计模式,它定义了操作中的算法框架,将算法的步骤延迟到子类中实现,提高了代码复用。文章通过示例介绍了模板方法模式的角色构成,包括抽象类和具体类,并展示了一个基于Java的示例程序,包括AbstractDisplay、CharDisplay和StringDisplay类。此外,文章还讨论了模板方法在InputStream类中的应用,并探讨了将模板方法模式与接口结合的可能性。
摘要由CSDN通过智能技术生成

什么是模板方法模式

在父类中定义处理流程的框架,在子类中实现具体处理的模式就称为模板方法模式,模板方法通过把不变的行为移到父类,去除子类中的重复代码,提高代码复用率。
如果要完成在某一些细节层次一致的一个过程或一系列步骤,旦其个别步骤在更详细的层次上的实现可能不同时,可以考虑用模板方法模式。

模板方法模式中的角色构成

模板方法模式类图

在这里插入图片描述

  • AbstractClass (抽象类)
    ​ AbstractClass角色负责实现模板方法以及声明模板方法中所使用到的抽象方法,这些抽象方法由子类ConcreteClass角色负责实现;模板方法作为具体方法,会给出一个顶级逻辑骨架,逻辑的组成步骤在相应的抽象方法中,会在子类中具体实现。在顶级逻辑中也可能调用一些具体方法。
    注意:模板方法不应被重写,所以应使用final修饰符
  • ConcreteClass (具体类)
    ​ ConcreteClass角色负责具体实现AbstractClass角色中定义的抽象方法,具体类中实现的方法将会在抽象类的模板方法中被调用;每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法的不同实现,从而使得顶级逻辑的实现各不相同。

示例程序

类组成表:
类名说明
AbstractDisplay包含open(),print(),close()三个抽象方法及模板方法display()
CharDisplay继承了AbstractDisplay类,实现了open(), print(), close()方法
StringDisplay继承了AbstractDispaly类,实现了open(), print(), close() 方法
TemplateMain测试类
示例程序类图

在这里插入图片描述

AbstractDisplay类:

​ AbstractDispaly类中有四个方法,具体实现的只有display()方法,其中open()、print()、 close()为抽象方法,方法的实际处理交给了继承的子类。

package com.example.templatemethod;

public abstract class AbstractDisplay {
    public abstract void open();    //交给子类去实现的抽象方法(1)open()
    public abstract void print();   //交给子类去实现的抽象方法(2)print()
    public abstract void close();   //交给子类去实现的抽象方法(3)close()
    public final void display() {   //本抽象类中实现的display()方法
        open();
        for (int i = 0; i < 5; i++) {
            print();
        }
        close();
    }
}
CharDisplay类:

​ AbstractDisplay类的一个子类,具体了实现父类中的三个抽象方法

package com.example.templatemethod;

public class CharDisplay extends AbstractDisplay{
    private char cd;

    public CharDisplay(char cd) {
        this.cd = cd;
    }

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

    @Override
    public void print() {
        System.out.print(cd); //显示构造函数接收的一个字符
    }

    @Override
    public void close() {
        System.out.println(">>");
    }
}
StringDisplay类:

​ AbstractDisplay类的另一个子类,实现了父类中的三个抽象方法,其具体实现与CharDisplay有所不同

package com.example.templatemethod;

public class StringDisplay extends AbstractDisplay{
    private String string;  //需要显示的字符串
    private int width;      //以字节为单位计算出的字符串长度

    public StringDisplay(String string) {
        this.string = string;
        this.width = string.getBytes().length;
    }

    @Override
    public void open() {
        printLine();
    }

    @Override
    public void print() {
        System.out.println("|" + string + "|"); //显示构造函数接受的字符串,并在前后加上"|"
    }

    @Override
    public void close() {
        printLine();
    }

    private void printLine() {
        for (int i = 0; i < width; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }
}
TempalteMain类:

​ 测试类

package com.example.templatemethod;

public class TemplateMain {
    public static void main(String[] args) {
        AbstractDisplay ad1 = new CharDisplay('Q');
        AbstractDisplay ad2 = new StringDisplay("hello,world");
        AbstractDisplay ad3 = new StringDisplay("String3");
        
        ad1.display();
        ad2.display();
        ad3.display();
    }
}
执行结果:
<<QQQQQ>>
-----------+
|hello,world|
|hello,world|
|hello,world|
|hello,world|
|hello,world|
-----------+
-------+
|String3|
|String3|
|String3|
|String3|
|String3|
-------+

拓展延伸

类的层次

​ 通常在理解类的层次时,容易站在子类的角度进行思考:

  • 在子类中可以使用父类中的哪些方法
  • 在子类中可以增加什么方法以实现新的功能
  • 在子类中重写父类的方法可以改变哪些程序行为
    转换角度,站在父类的角度进行思考,通过声明抽象方法,将方法的具体实现交给子类。也就是说子类具有实现在父类中所声明的抽象方法的责任,这种责任被称为“子类责任”(subclass reponsibility)
InputStream中的模板方法

​ java.io.InputStream中有一个抽象方法read(),它会被InputStream的模板方法read(byte b[], int off, int len) 循环调用。InputStream的子类负责具体实现"读取一个字节"的操作,而InputStream中定义的模板方法只负责"将指定数量的字节读取到数组中的指定位置"的操作。

public abstract int read() throws IOException;
public int read(byte b[], int off, int len) throws IOException {
   if (b == null) {
       throw new NullPointerException();
   } else if (off < 0 || len < 0 || len > b.length - off) {
       throw new IndexOutOfBoundsException();
   } else if (len == 0) {
       return 0;
   }

   int c = read();
   if (c == -1) {
       return -1;
   }
   b[off] = (byte)c;

   int i = 1;
   try {
       for (; i < len ; i++) {
           c = read();
           if (c == -1) {
               break;
           }
           b[off + i] = (byte)c;
       }
   } catch (IOException ee) {
   }
   return i;
}
画蛇添足

​ 尝试将抽象类改写成接口,将其中的模板方法改写成Java 8加入的接口默认方法

IAbstractDisplay接口:

​ 包含三个抽象方法open()、print()、close(),一个默认方法disPlay()替换原抽象类中的模板方法disPlay()

package com.example.templatemethod.interfaceImpl;

public interface IAbstractDisplay {
    void open();
    void print();
    void close();

    default void disPlay() {
        open();
        for (int i = 0; i < 5; i++) {
            print();
        }
        close();
    }
}
CharDisPlayImpl类:

​ IAbstractDisplay接口的一个实现类,具体实现了接口当中的三个抽象方法

package com.example.templatemethod.interfaceImpl;

public class CharDisplayImpl implements IAbstractDisplay{
    private char cd;

    public CharDisplayImpl(char cd) {this.cd = cd;}

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

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

    @Override
    public void close() {
        System.out.println(">>");
    }
}
StringDisplayImpl类:

​ IAbstractDisplay接口的另一个实现类,实现了接口当中的三个抽象方法,与CharDisplayImpl的具体实现不同

InterfaceImplMain类:

​ 测试类

package com.example.templatemethod.interfaceImpl;

public class InterfaceImplMain {
    public static void main(String[] args) {
        IAbstractDisplay ad1 = new CharDisplayImpl('Q');
        IAbstractDisplay ad2 = new StringDisplayImpl("hello,world");
        IAbstractDisplay ad3 = new StringDisplayImpl("String3");

        ad1.disPlay();
        ad2.disPlay();
        ad3.disPlay();
    }
}
执行结果:
<<QQQQQ>>
-----------+
|hello,world|
|hello,world|
|hello,world|
|hello,world|
|hello,world|
-----------+
-------+
|String3|
|String3|
|String3|
|String3|
|String3|
-------+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值