模板方法模式
定义
Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
代码实现
准备
我们先抽象出一个汽车类,将汽车需要的动作都抽象进来,然后定义一个算法骨架,将这些抽象的动作组织起来,形成一个动作流程。由于这些动作是抽象的,我们需要具体实现这些动作,当我们创建一个实现类的对象,我们就会继承这个算法骨架,这就让我们的实现类只需要实现动作就行了,不需要再自定义动作流程。
模板方法模式
创建一个汽车抽象类,抽象出所有汽车都需要的共同动作,并将所有共同动作组织成一个使用流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public abstract class Car { protected abstract void start () ; protected abstract void stop () ; protected abstract void alarm () ; protected abstract void engineBoom () ; public void run () { this .start(); this .engineBoom(); this .alarm(); this .stop(); } }
然后实现一个东风汽车这个实现类,这个实现类只需要实现汽车抽象类的抽象动作。我们使用东风汽车时需要调用的使用方法就通过继承汽车抽象类继承下来了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class DongFeng extends Car { @Override public void start () { System.out.println("东风启动起来了" ); } @Override public void stop () { System.out.println("东风停下来了" ); } @Override public void alarm () { System.out.println("东风拉起汽笛" ); } @Override public void engineBoom () { System.out.println("东风引擎启动起来了" ); } }
场景实现类,我们只需要创建东风汽车这个对象,就能调用汽车抽象类中的run方法。
1 2 3 4 5 6 7 8 9 10 public class App { public static void main (String[] args) { DongFeng dongFeng = new DongFeng(); dongFeng.run(); } }
模板方法模式的扩展
在抽象类中实现一个钩子函数,这个钩子函数能够被子类重写,我们通过更改子类重写的钩子函数结果,覆盖父类的钩子函数结果,从而改变父类中的动作逻辑,改变结果。
创建一个汽车抽象类,这个抽象类中有一个钩子函数实现。在实现逻辑中加入了一个判断,通过判断钩子函数的结果走不同的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public abstract class Car { protected abstract void start () ; protected abstract void stop () ; protected abstract void alarm () ; protected abstract void engineBoom () ; public void run () { this .start(); this .engineBoom(); if (isAlarm()){ this .alarm(); } this .stop(); } protected boolean isAlarm () { return true ; } }
创建一个子类实现,这个子类将父类的钩子函数重写,并让我们能更改钩子函数的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class DongFeng extends Car { private boolean alarmFlag = true ; @Override public void start () { System.out.println("东风启动起来了" ); } @Override public void stop () { System.out.println("东风停下来了" ); } @Override public void alarm () { System.out.println("东风拉起汽笛" ); } @Override public void engineBoom () { System.out.println("东风引擎启动起来了" ); } protected boolean isAlarm () { return this .alarmFlag ; } public void setAlarm (boolean flag) { this .alarmFlag = flag ; } }
最后的场景实现类,我们能通过set方法更改父类中的逻辑,从而改变结果。
1 2 3 4 5 6 7 8 9 10 11 public class App { public static void main (String[] args) { DongFeng dongFeng = new DongFeng(); dongFeng.setAlarm(false ); dongFeng.run(); } }
应用场景
多个子类共有方法时,并且逻辑相同。
重要、复杂的核心算法设计为模板在父类实现,细节部分有子类实现。
模板方法模式优缺点
优点
封装不变部分,扩展可变部分;就是将不变部分封装到抽象类中,可变部分就通过继承来继续扩展。不变部分能被继承子类调用。
提取公共代码,便于维护。子类继承的是每个子类的特性,而每个子类都需要的公共代码就封装在抽象类中。
行为由父类控制,子类实现。父类将行为抽象,让子类具体按照自己的特征实现。
缺点
模板方法模式颠倒了子类和父类的作用。父类本来只负责声明抽象的部分,子类实现这些抽象部分,其他具体实现由子类自己实现,子类不会对父类产生影响。但是模板方法下,父类不仅需要声明抽象行为,还有具体实现,子类只需要实现抽象部分,这样子类会对父类产生影响。