本文共 1282 字,大约阅读时间需要 4 分钟。
Define the skeleton of an algorithm in an operation, deferring some steps to subclass. Template Method lets subclasses redefine certain steps of an algorithm without change the algorithm’s structure;
模板方法定义一个操作中的算法框架,将一些步骤延迟到子类中,使得子类可以重新定义一些特定步骤而不改变算法的结构;
模板方法模式体现了“找到变化、封装变化”这一面向对象设计的中心。在一些场景中,算法的框架的不变的,比如去食堂吃饭这一过程,去食堂–>打饭–>在食堂吃饭–>离开,这个流程不变的,变化的是去哪个食堂(甚至还包括怎么去食堂!骑车?步行?)、买什么样的饭(米饭?面条?)、使用什么样的餐具(筷子?刀子?叉子?勺子?)以及从哪个门离开。这些变化的东西被抽离出来放到子类实现,从而使抽象父类在一定程度上保持了稳定(算法框架不变,就像把大象装进冰箱只需要三步一样~)而且算法的最终实现也拥抱了变化;
模板方法,自然要有一个模板,这个模板由抽象父类定义即可;子类则为模板提供个性化的实现;
doSomething中依次调用step1、step2、step3,为模板方法; 子类AlgorithmImplementor1和2分别提供step2的实现即可; Client依赖于AlgorithmClass;模板类的职责便是实现算法,符合单一职责原则;
抽象父类只定义了算法框架中的一部分,要实现完整的算法功能,还需要具体子类;所以“所有父类可以出现的地方,均可使用子类对象代替”,满足里氏替换原则;
子类在实现算法相关的步骤时难免会依赖其他对象,这时抽象父类也应该依赖对应的抽象类,而不是具体类;
Client不需要了解算法的具体实施,该过程由父类定义、子类实现;对Client屏蔽了算法细节;
如果在子类中使用了多个对象的组合,理应满足接口隔离原则;
在父类的角度来看,定义一个良好的算法框架尤为重要,在保持稳定的同时也要拥抱变化,利用钩子方法可以使得父类在定义算法框架时保持一定的灵活性,从而对“修改”关闭;
钩子是一种申明在抽象类中的方法,但是只有空的或者默认的实现,钩子的存在使得子类可以对算法的不同点进行挂钩;常见的用途是让子类决定算法的执行流程,比如在上述去食堂吃饭的流程中,如果该食堂允许打包饭菜,那么打饭后就不一定执行“吃饭”,也有可能“打包”,到底怎样是由子类决定的,所以父类应该设置这样一个“钩子”:
... if(允许打包()&&想打包()){ 打包(); }else{ 在食堂吃(); } ....
以上允许打包()和想打包()即为钩子方法~