模板方法模式(Template Method Pattern):定义一个操作中算法的骨架,而将一些步骤延迟到子类中去实现,使子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
类图及角色
主要包括两种角色:抽象模板类和具体类
抽象模板类:定义一个或多个抽象操作,由子类去实现,这些操作称为基本操作。
定义并实现一个具体操作,这个具体操作通过调用基本操作确定顶级逻辑,这个具体操作称为模板方法。
具体类:实现抽象模板类所定义的抽象操作。
模板方法模式的目的
有一些通用的方法,将这些方法抽象出来(也可是接口的方法),把具体的实现推迟。
最经典的例子是排序。Java.util.collection类将sort方法定义为一个模板方法,将其中的比较交给子类实现,比如我们用的冒泡、选择、快速排序等。
《大话设计模式中》中商场计算不同商品的价格(打几折)。
缺陷
- 概念复杂性。从面向对象方法的本质来讲,父类负责抽象,子类负责具体。模板方法正好反过来了,父类实现了大部分的功能,子类实现少数的方法。
- 实现复杂性。这种重用方式的代价就是每个子类身上都背负了父类强加给它的包袱。
1、父类控制子类的业务逻辑,这就是控制反转。子类可以实现父类的可变部分,但是不能改变父类的业务逻辑。
2、当子类过多时,以防子类修改父类的业务逻辑,可以将模板方法定义为final。
3、模板方法模式一般在框架中频繁地使用,使得框架对关键逻辑进行集中控制。
//模板方法抽象类:不变的部分给出具体实现,变化的部分封装为抽象方法延迟到子类实现
public abstract class AbstractTemplate {
public abstract void primitiveOperation1();
public abstract void primitiveOperation2();
public void templateMethod() {
primitiveOperation1();
primitiveOperation2();
System.out.println("模板方法结束\n");
}
}
//具体类
public class ConcreteClassA extends AbstractTemplate {
@Override
public void primitiveOperation1() {
System.out.println("具体类A的方法1实现");
}
@Override
public void primitiveOperation2() {
System.out.println("具体类A的方法2实现");
}
}
//具体类
public class ConcreteClassB extends AbstractTemplate {
@Override
public void primitiveOperation1() {
System.out.println("具体类B的方法1实现");
}
@Override
public void primitiveOperation2() {
System.out.println("具体类B的方法2实现");
}
}
//客户端
public class TemplateClient {
public static void main(String[] args) {
AbstractTemplate abstractTemplate;
abstractTemplate = new ConcreteClassA();
abstractTemplate.templateMethod();
abstractTemplate = new ConcreteClassB();
abstractTemplate.templateMethod();
}
}