模板方法模式是行为型设计模式的一种。它定义了一个算法的骨架,并将某些步骤的实现延迟到子类中。模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤。
模板方法模式的核心在于:
- 封装算法的骨架:通过父类中的模板方法定义算法的执行顺序和框架,保证算法结构的一致性。
- 委派细节实现:通过抽象方法的方式,允许子类根据自己的需求来提供具体实现,增强了算法的灵活性。
一、模板方法模式的结构
模板方法模式的核心是一个“模板方法”,它通常是一个在父类中定义的具体方法,里面包含了步骤的调用,而步骤的具体实现交给子类。下面是模板方法模式的基本结构:
-
抽象类(Abstract Class):
定义一个模板方法,包含了算法的框架。模板方法通常是具体的方法,它调用一些抽象方法,并通过这些抽象方法将某些步骤的实现委托给子类。
声明一些抽象方法,这些方法将由子类具体实现,代表算法中的具体步骤。 -
具体类(Concrete Class):
实现抽象类中的抽象方法,提供每个步骤的具体实现。 -
模板方法(Template Method):
在抽象类中定义的具体方法,它为整个算法提供了固定的执行流程和框架。子类可以在模板方法的框架中执行其特定的步骤。
二、模板方法模式的实现
假设我们正在设计一个做菜的程序。做菜的步骤大致是固定的:起锅,热油,加菜,加调料,出锅。不同的菜肴有相同的烹饪步骤,可以通过模板方法来实现不同菜肴的流程。
-
抽象类
public abstract class AbstractCook {public void cookProcess(){begin();pourOil();addVegetable();addSauce();end();}public void begin(){System.out.println("起锅");}public void pourOil(){System.out.println("烧油");}public abstract void addVegetable();public abstract void addSauce();public void end(){System.out.println("出锅");} }
-
具体类
public class CookCabbage extends AbstractCook{@Overridepublic void addVegetable() {System.out.println("加白菜");}@Overridepublic void addSauce() {System.out.println("加醋,加盐");} }
public class CookCarrot extends AbstractCook{@Overridepublic void addVegetable() {System.out.println("加胡萝卜");}@Overridepublic void addSauce() {System.out.println("加盐,加味精");} }
-
客户端
public class Client {public static void main(String[] args) {AbstractCook cook = new CookCabbage();cook.cookProcess();} }
-
运行结果
三、模板方法模式的优缺点
优点:
- 代码复用:模板方法模式将算法的公共部分提取到父类中,避免了重复代码,提高了代码复用性。
- 灵活性:尽管算法框架是固定的,但通过子类可以实现特定步骤的变化,符合开闭原则(对扩展开放,对修改封闭)。
- 控制反转:模板方法模式通过父类控制了算法的结构,子类只需关注具体的实现细节,不必关心算法框架。
缺点:
- 过度设计:如果算法结构简单,或者算法变化较小,使用模板方法模式可能会显得过于复杂,增加了设计的复杂度。
- 对子类依赖:子类必须依赖父类提供的模板方法和结构,这可能导致子类与父类之间耦合较高。子类只能按照父类定义的步骤来实现,无法自由调整流程。
四、模板方法模式的应用场景
模板方法模式适用于以下情况:
-
算法框架稳定,步骤可变:
当算法框架的结构不变,但具体的实现步骤可以变化时,模板方法模式是非常合适的选择。子类只需要实现算法中的具体步骤即可,而不需要关心框架本身的设计。 -
操作顺序固定,步骤可扩展:
比如游戏中的回合制战斗,或者一些具有固定执行顺序的流程,模板方法模式可以帮助固定这些步骤的顺序,并允许不同的子类根据需要改变具体的操作。 -
避免代码重复:
如果某个系统中有多个操作流程,且这些流程中有重复的步骤,那么模板方法模式可以有效地提取出这些共通的部分,从而减少重复代码。 -
框架的设计:
模板方法模式经常用于设计框架类。一个框架可以提供一个模板方法,子类在继承框架时只需实现其中的一些步骤。
现实生活中的例子:
- 软件测试框架:在自动化测试框架中,测试步骤往往包括初始化、执行测试、清理环境等,模板方法模式可以帮助确保这些步骤的一致性,而允许子类定义具体的测试方法。
- 文件处理:比如读取CSV文件、XML文件、JSON文件等,虽然不同的文件格式有不同的解析方法,但读取文件、解析文件和处理数据的步骤通常是相似的,模板方法模式可以用来构建一个统一的文件处理框架。
五、模板方法模式与其他设计模式的关系
模板方法模式与其他行为型设计模式有一些相似性和不同之处:
-
模板方法模式 vs 策略模式:
- 模板方法模式:定义了算法的骨架,允许子类实现具体的步骤,但整体算法框架不可改变。
- 策略模式:允许算法在运行时改变,客户端可以选择不同的策略来完成任务,通常是通过组合来实现不同的策略,而不是通过继承来实现算法的变化。
-
模板方法模式 vs 状态模式:
- 状态模式:允许对象根据其内部状态的不同来改变其行为,状态是动态变化的。
- 模板方法模式:则是在父类中定义一个固定的算法框架,子类仅需要实现某些步骤,而状态变化并不会影响整个算法的框架。