行为型模式

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责分配。

行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或者聚合在对象间分配行为。由于组合关系或者聚合关系比继承关系耦合度第,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

模板方法模式

去银行办理一些业务一般都需要经过以下4个步骤:1.取号 2.排队 3.办理具体业务 4. 对工作人员评分。每个人都会按照顺序经历这4个步骤,但是每个人可能办理的业务不同。

我们可以将固定的过程放到父类中统一实现,将变化的东西放到子类中去实现。

案例

public abstract class BankService {
    // 抽象方法
    public abstract void handleBusiness();
    // 模板方法
    public final void service() {
        System.out.println("1.取号");
        System.out.println("2.排队");
        handleBusiness();
        System.out.println("4.评分");
    }
}

使用模板方法模式就是把公共的代码抽取到父类中,使得子类只需要变的东西,使得子类的代码非常简洁。

public class GetMoneyBankService extends BankService {
    @Override
    public void handleBusiness() {
        System.out.println("3.办理取钱业务");
    }
}
public class PutMoneyBankService extends BankService {
    @Override
    public void handleBusiness() {
        System.out.println("3.办理存钱业务");
    }
}
public class Client {
    public static void main(String[] args) {
        BankService bankService = new PutMoneyBankService();
        bankService.service();

        bankService = new GetMoneyBankService();
        bankService.service();
    }
}

模板方法套路

  • 模板类是抽象类,使用abstract修饰
  • 模板方法使用final修饰,并实现具体的步骤。
  • 抽象方法使用abstract。
  • 具体类需要继承模板类并实现模板类中的抽象方法。

优缺点

优点:

  • 提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。
  • 实现了反向控制:通过一个父类调用子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制,并符合开闭原则。

缺点:

  • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码的阅读难度。

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;
    }
}