模板方法模式在一个基类中(抽象类)定义了一个算法(执行过程)的骨架,骨架中有一些步骤可能需要子类自己实现,模板方法模式固定了算法骨架的同时又允许子类自己定义算法中的某些步骤。
比如headfirst中的咖啡和茶的例子,泡咖啡和泡茶的算法其实一样,1烧开水-2冲泡-3倒入杯子-4加作料,只有2/4两步是不一样的。所以我们可以写一个抽象类并定义一个模板方法确定算法框架:
public abstract class Drink {
void getDrink(){
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
... ...
}
void pourInCup() {
... ...
}
}
因为2/4两步子类的实现不一样,所以定义为抽象方法让子类自己实现。这样getDrink()就是一个模板方法,它定义了泡茶和泡咖啡共同的算法骨架。
在JDK中也有类似的模式实现,如InputStream中有个read(byte b[], int off, int len) 方法:
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(); //该方法调用了read(),而read()是一个抽象方法,是有子类自己决定如何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()是一个抽象方法:
public abstract int read() throws IOException;
所以我们自己写一个类继承InputStream时必须重写read方法,包括JDK中已有的InputStream子类FileInputStream就重写了:
public int read() throws IOException {
return read0();
}
private native int read0() throws IOException; //这里也可以看出文件操作是进入内核态进行了系统调用
网友评论