定义
定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现;
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
适用场景
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;
- 各个子类中公共的行为被提取出来并集中到一个公共父类中,从而避免代码重复。
优点和缺点
优点
- 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
- 它在父类中提取了公共部分代码,便于代码复用;
- 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点
- 对每个不同的实现都需要定义一个子类,这会导致类的数量增加,系统更加庞大,设计也更加抽象,间接增加的系统实现的复杂度。
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码的阅读难度。
- 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都需要改一遍。
代码实现
假设一个场景,我们要生产电脑,每个厂家生产电脑配置的东西不一样
首先创建抽象类,限制创建电脑的模板
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
| public abstract class AComputer {
protected final void assembleComputer(){ principal(); displayer(); keyboard(); if (needMouse()){ mouse(); } }
protected final void principal(){ System.out.println("生产主机"); }
protected final void displayer(){ System.out.println("生产显示器"); }
abstract void keyboard();
protected final void mouse(){ System.out.println("生产鼠标"); }
protected boolean needMouse(){ return false; } }
|
创建子类,继承抽象类,实现抽像方法
1 2 3 4 5 6 7 8 9
| public class AsusComputer extends AComputer{
@Override void keyboard() { System.out.println("华硕机械键盘"); } }
|
子类重写钩子方法,控制父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class LenovoComputer extends AComputer{ @Override void keyboard() { System.out.println("联想键盘"); }
@Override protected boolean needMouse() { return true; } }
|
或者通过入参来控制父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class HpComputer extends AComputer{
private boolean needMouseFlag = false;
public HpComputer(boolean needMouseFlag) { this.needMouseFlag = needMouseFlag; }
@Override void keyboard() { System.out.println("惠普键盘"); }
@Override protected boolean needMouse() { return this.needMouseFlag; } }
|
UML类图