目录
一、基本概念
二、UML类图
三、角色设计
四、代码实现
案例一
案例二
五、总结
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类当中,使得子类可以不改变该算法结构的情况下重定义该算法的特定步骤,即在一个抽象类中公开定义了执行某一方法的模板,然后子类可以按需重写方法实现自己特有的逻辑。
通俗的来讲其实就好比做一道菜一样,同样的步骤每个人做出来的味道缺大相径庭,这个步骤就可以理解为模板方法模式,采用固定的步骤去做,但是如何去实现就看自己怎么想了。
角色 | 描述 |
---|---|
基类 | 抽象类,在基类中定义或声明了一系列基本操作,这些操作可以是具体或者是者抽象的,每一个操作都对应算法的一个步骤,这些步骤在其派生类中都可以重定义。基类规定了算法的流程框架,模板方法由基类定义或声明的一系列基本操作按照一定流程实现。 |
子类 | 实现在基类中声明的抽象方法,也可以覆盖在基类中已经实现的方法。 |
假设做一盘菜固定有3个步骤,分别是热锅、烹饪和出锅,因为步骤是固定的,只有烹饪手法不同,只需要重写cooking方法即可。
定义一个抽象模板类:
注:为了防止恶意的操作,一般模板方法前面会加上final关键字,不允许被覆写。
public abstract class AbstractClass {
final void operation(){
this.start();
this.cooking();
this.end();
}
private void start(){
System.out.println("热锅...");
}
protected abstract void cooking();
private void end(){
System.out.println("出锅...");
}
}
具体模板实现类:
public class BraisedFish extends AbstractClass{
@Override
protected void cooking() {
System.out.println("做红烧肉...");
}
}
客户端:
public class Client {
public static void main(String[] args) {
AbstractClass abstractClass = new BraisedFish();
abstractClass.operation();
}
}
运行结果如下:
假设做一杯奶茶有三个固定的步骤,分别是选材、加料和打包,这边也同样采用相同的逻辑进行实现。
定义制作奶茶的抽象类:
public abstract class MakeTeaMilk {
final void make(){
select();
addCondiments();
pack();
}
/**
* 选果茶/奶茶
*/
abstract void select();
/**
* 添加配料
*/
abstract void addCondiments();
/**
* 打包
*/
private void pack(){
System.out.println("奶茶打包!");
}
}
制作一杯果茶:
/**
* 果茶
* @author HTT
*/
public class FruitTeaMilk extends MakeTeaMilk{
@Override
void select() {
System.out.println("选取柠檬汁");
}
@Override
void addCondiments() {
System.out.println("添加补丁");
}
}
客户端:
public class Client {
public static void main(String[] args) {
MakeTeaMilk fruitTeaMilk = new FruitTeaMilk();
fruitTeaMilk.make();
}
}
运行结果如下:
优点:
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现细节。
缺点:
1、每一个不同的实现都需要一个子类。
2、发生扩展时需要修改抽象类。
应用场景:
1、多个子类有公有的方法,并且逻辑基本相同时。
2、重要的、复杂的算法,可以把核心算法设计为模板方法,周边的相关逻辑在子类中实现。
3、有确定的培训流程或标准流程逻辑时。
符合的设计原则:
1、单一职责原则(Single Responsibility Principle)
抽象类只负责模板方法的定义,子类实现自己的职责逻辑。
2、开闭原则(Open Closed Principle)
可以通过继承抽象类来扩展新的子类,而不需要修改抽象类代码。
3、里氏替换原则(Liskov Substitution Principle)
继承抽象类的子类可以扩展新的行为,但不会破坏抽象类原有逻辑。
4、依赖倒转原则(Dependency Inversion Principle)
父类和子类都依赖于抽象接口,不存在具体依赖关系。
5、接口隔离原则(Interface Segregation Principle)
模板方法中只定义了子类需要实现的方法签名,避免不必要依赖。
模板方法模式将通用流程封装在父类的模板方法中,通过调用钩子方法来实现步骤的变化,思想是继承的重用和扩展。既保持了算法结构稳定,也灵活地实现了可变化的部分。适用于有规范定制化需求的场景中。