引子
我们发现茶喝咖啡有相似的地方,当然,泡茶喝和泡咖啡也有相似的地方。
咖啡和茶的类:
//咖啡类
public class Coffee {
//准备咖啡
void prepare(){
//加入咖啡
addCoffee();
//加入水
boilWater();
//加牛奶
addMilk();
}
private void addCoffee(){
System.out.println("add coffee!");
}
private void boilWater(){
System.out.println("boil water!");
}
private void addMilk(){
System.out.println("boil milk!");
}
}
//茶类
public class Tea {
//准备茶
void prepare(){
addTea();
boilWater();
addLemon();
}
private void addTea(){
System.out.println("add tea!");
}
private void boilWater(){
System.out.println("boil water!");
}
private void addLemon(){
System.out.println("boil lemon!");
}
}
出现重复的代码,两个类都有倒入水方法,我们需要把这些重复代码抽取出来
第一版的实现
public abstract class Beverage {
//因为prepare在两个类中不一样,所以只能作为抽象方法
abstract void prepare();
//两个类中都一样,可以提取出来
private void boilWater(){
System.out.println("boil water!");
}
}
但是我们抽象的不够彻底,另外两个方法虽然不一样,但是方法相似。
比如咖啡的addCoffee 与茶的addTea,咖啡的addMilk 与茶的addLemon,虽然动作不一样,方式行为方式一样,我们可以用一个方法来代替相似的行为。
public abstract class Beverage {
// 因为prepare在两个类中不一样,所以只能作为抽象方法
void prepare() {
//冲泡
brew();
// 加入水
boilWater();
// 加配料
addBurden();
}
//抽象方法由子类实现
abstract void brew();
abstract void addBurden();
// 两个类中都一样,可以提取出来
private void boilWater() {
System.out.println("boil water!");
}
}
只要子类实现两个抽象的方法就行了。
定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
其实我们对这些代码一点都不陌生,因为模板方法可以说是最常用的方法之一。
public abstract class Beverage {
// 因为prepare在两个类中不一样,所以只能作为抽象方法
final void prepare() {
//冲泡
brew();
// 加入水
boilWater();
// 加配料
addBurden();
}
//抽象方法由子类实现
abstract void brew();
abstract void addBurden();
// 两个类中都一样,可以提取出来
final void boilWater() {
System.out.println("boil water!");
}
//钩子函数
void hook(){}
}
我们一般发由子类实现的函数用abstract修饰,已实现的方法final防止子类修改,也可以加入一个普通的钩子函数,子类可以实现,也可以不实现
在Swing中的JFame里的paint就是一个钩子函数,当子类实现paint时,就会运行paint里的函数。