继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用!
6.行为型模式
6.1 概述
6.1.1 特点
- 用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎么相互协作共同完成单个对象都无法单独完成任务
- 涉及算法与对象间职责的分配
6.1.2 分类
6.1.2.1 类行为模式
- 采用继承机制在类间分派行为
- 包含:模板方法模式、解释器模式
6.1.2.2 对象行为模式
- 采用组合或聚合在对象间分派行为
- 具有更大灵活性
- 包含:策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式
6.2 模板方法模式
6.2.1 定义
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
6.2.2 结构
- 抽象类:负责给出一个算法的轮廓和骨架,由一个模板方法和若干个基本方法构成
- 模板方法:实现算法的各个步骤方法,是模板方法组成部分,分为
- 抽象方法:由抽象类声明,由其具体子类实现
- 具体方法:由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承
- 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXXX,返回值类型为Boolean型
- 具体子类:实现抽象类中所定义的抽象方法和钩子方法,是一个顶级逻辑的组成步骤
6.2.3 案例(炒菜)
- 抽象类
public abstract class AbstractMethod {
// 模板方法定义
public final void cookProcess() {
pourSoil();
heatSoil();
pourVegetable();
pourSauce();
fry();
}
private void pourSoil() {
System.out.println("倒油");
}
// 热油,步骤一样,直接实现
private void heatSoil() {
System.out.println("热油");
}
// 倒菜,不一样,倒菜心,倒包菜
public abstract void pourVegetable();
// 倒配料,也不一样
public abstract void pourSauce();
// 翻炒一样
private void fry() {
System.out.println("翻炒---直到熟透");
}
}
- 具体方法-炒菜心
public class ConcreteMethod extends AbstractMethod{
@Override
public void pourVegetable() {
System.out.println("倒菜心");
}
@Override
public void pourSauce() {
System.out.println("倒配料蒜蓉");
}
}
- 测试
public static void main(String[] args) {
ConcreteMethod caixin = new ConcreteMethod();
caixin.cookProcess();
}
- 结果
6.2.4 优缺点
6.2.4.1 优点
- 提高代码复用性:将相同部分代码放在抽象父类汇总,将不同代码放入不同子类中
- 实现了反向控制:通过父类调用其子类操作,通过对之类具体实现扩展不同行为,实现反向控制,符合“开闭原则"
6.2.4.2 缺点
- 对每个不同的实现需要定义子类,这会导致类的个数增加,系统更加庞大,设计更加抽象
- 父类中抽象方法由子类实现,子类执行结果会影响父类结果,导致一种反向的控制结构,提高了代码阅读的难度
6.2.5 使用场景
- 算法的整体步骤固定,但其中个别部分易变,此时可使用模板方法模式,将容易易变的部分抽象出来,供子类实现
- 需要通过子类来决定父类算法中某步骤是否执行,实现子类对父类的反向控制
6.2.6 JDK源码
InputStream类使用了模板方法弄死,在InputStream类中定义了多个read()
方法,如下:
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;
}
//调用无参构造方法read(),每次读取一个字节数据
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;
}
}
分析:
无参方法read()
是抽象方法,要求子类必须实现,read(byte b[])
方法调用read(byte b[],int off,int len)
方法,重点是此方法