其实这三者之间没什么可区分的,因为他们是不同领域的概念。但是他们非常相似都是在抽象的定义了方法,然后子类实现它。他们都是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中不具备传递函数指针这一语法特性,于是利用接口来实现方法回调。它注重的是对方法的描述——方法名是什么、方法参数有什么、返回值如何。 模板方法模式利用抽象类,注重都是由父类来控制算法逻辑,子类提供具体每个算法步骤的实现。 钩子方法其实就是普通的抽象类多态,它在模板方法模式中提供了改变原始逻辑的空间。