设计模式之模板方法模式

设计模式之模板方法模式

1. 概括

如果有多个类中有着大致相同的算法,只是有算法中有着细微的不同,那么可以使用模板方法模式
模式方法模式在父类中定义了一系列的算法框架,允许子类在不修改结构的情况下,重写算法的特定步骤
模板方法建议把一系列算法,抽取成一个个的步骤,步骤即为方法,这些方法如果是每个子类共有步骤,可以是具体方法;步骤细节不同之处,声明成抽象方法,让每个子类单独去实现 (不包括模板方法)

2. 结构

  • 抽象类:定义了一个模板方法,一系列基本方法
    • 模板方法:用特定的步骤去调用基本方法,不可被重写
    • 基本方法:每个子类的算法公共逻辑是有实现的方法,不同的逻辑为抽象方法
    • 钩子方法:一般用于逻辑判断,返回值是bool类型,可以是有实现体的方法,也可是抽象方法
  • 具体类:继承或实现抽象类,实现其中的方法

3. 使用场景

  • 当希望客户端实现某个特定的算法步骤,而不是其结构
  • 当多个类有着相似的步法步骤,只有一些细微的不同

4. 优缺点

  • 优点:
    • 开闭原则
    • 提高代码复用
  • 缺点:
    • 父类的代码中【反向调用】子类,增加代码阅读难度
    • 子类【有可能】会重写父类中,已经有实现体的方法,而违反里氏替换原则

5. 实现

  • 在银行办理业务时,取号、排队、办理业务、评分这些步骤中
  • 取号、排队、评分,这些是相同的,步骤是相同的,而办理的业务可能不同
  • 取号、排队、评分为有实现体的方法,办理业务方法为抽象方法,用一个模板方法去按顺序调用这些方法
  • 抽象类
public abstract class BankService {

    public void takeNo() {
        System.out.println("取号");
    }

    public void lineUp() {
        System.out.println("排队");
    }

    // 具体不同的算法
    public abstract void serviceHandle();

    public void score() {
        System.out.println("评分");
    }

    // TODO 模板方法
    public final void service() {
        takeNo();
        lineUp();
        serviceHandle(); // TODO 【要点】 由父类调用子类具体实现的方法【反向调用】
        score();
    }
}
  • 具体类
public class BankDeposit extends BankService{
    @Override
    public void serviceHandle() {
        System.out.println("存款业务");
    }
}
public class BankTransfer extends BankService{
    @Override
    public void serviceHandle() {
        System.out.println("转账业务");
    }
}
  • 调用
public class Client {
    public static void main(String[] args) {
        BankService service = new BankTransfer();
//        BankService service = new BankDeposit();
        service.service();
    }
}

6. 在JDK中的应用

public abstract class InputStream implements Closeable {
	
	// 子类重写的具体方法
    public abstract int read() throws IOException;

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

	//模板方法,去调用上面的方法
    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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值