其实这三者之间没什么可区分的,因为他们是不同领域的概念。但是他们非常相似都是在抽象的定义了方法,然后子类实现它。他们都是java多态特性的实践。
概念领域区分:
1.正确的说应该就是模板方法模式,模板方法模式提供模板方法,这个方法是一个模板算法,或者说在方法的调用顺序上固定了一个模板。
2.回调方法,是固定一个方法外观,java中通过接口实现。
3.钩子方法,是一个抽象类提供空实现,子类进行选择性重写的方法。钩子方法也出现在模板方法模式中。
区分
其实就是主要是模板方法模式和回调模式的区分。简单来说就是模板方法模式使用的是抽象类,既然要定义算法逻辑,那么就一定需要一个实现算法的方法
模板方法模式与钩子方法
详见《head first设计模式》第8章——模板方法模式。
模板方法模式使用抽象类来定义方法调用的逻辑。子类继承抽象类,从而获取到了这个逻辑,然后提供某些具体方法实现。
abstract class AbstractClass{
/*
*模板方法,提供一种模板算法或者说在方法的调用顺序上固定了一个模板。
*/
final void templateMenthod(){
primitiveOperation1();
primitiveOperation2();
if(hookOperation()){
concreteOperation();
}
}
abstract void primitiveOperation1();
abstract void primitiveOperation2();
void concreteOperation(){
//抽象类提供了某些实现
}
boolean hookOperation(){
return true;//钩子方法,子类可以实现这个方法,也可以不
}
}
class ConcreteClass1 extends AbstractClass{
@override
void primitiveOperation1(){
System.out.println("con 1.1");
}
@override
void primitiveOperation2(){
System.out.println("con 1.2");
}
/*
*重写了钩子方法,重置了判断逻辑
*/
@override
boolean hookOperation(){
if(getUserInput().toLowerCase().startsWith("y")){
return true;
}else{
return false;
}
}
private String getUserInput(){
String answer = null;
BufferedReader in = new BufferedReader (new InputStream(System.in));
try{
answer = in.readline;
}catch (IOException e){
}
if (answer == null){
return "no";
}
return answer;
}
}
上面提供了一个子类实现了某些方法实现,最终使templateMenthod()这个方法能够正常运行。
class ConcreteClass2 extends AbstractClass{
@override
void primitiveOperation1(){
System.out.println("con 2.1");
}
@override
void primitiveOperation2(){
System.out.println("con 2.2");
}
}
public class Test{
public static void main(String[] args){
ConcreteClass1 c1 = new ConcreteClass1();
ConcreteClass2 c2 = new ConcreteClass2();
c1.templateMenthod();
c2.templateMenthod();
}
}
AbstractClass定义了逻辑,子类提供了实现,这种设计模式解耦了算法逻辑与具体实现,完成了算法的代码复用。而钩子方法给子类在一定程度上更改原先的逻辑,提供了一定的灵活性。
回调方法
之前写过一篇理解java中回调机制的文章,具体可以看一看。
其实在C语言和js中都可以直接传递函数引用(要正确理解回调可以先看一下js回调函数的示例),而java中是没有这一语法特性的 。那么我们想要完成回调就需要传递一个对象,然后在调用这个对象特定方法,通过接口我们约定方法的参数、返回值、方法名这些要素,使用的时候把具体的接口实现传递过去,就实现了方法的回调。
可见回调用到的是接口,而不是模板方法模式里面的抽象类。
总结
回调方法和模板方法使用了抽象方法,
回调利用的接口,由于java中不具备传递函数指针这一语法特性,于是利用接口来实现方法回调。它注重的是对方法的描述——方法名是什么、方法参数有什么、返回值如何。
模板方法模式利用抽象类,注重都是由父类来控制算法逻辑,子类提供具体每个算法步骤的实现。
钩子方法其实就是普通的抽象类多态,它在模板方法模式中提供了改变原始逻辑的空间。