定义:在父类中定义处理流程的框架,在子类中实现具体的处理就成为模板方法模式(Template Method),
假设我们制定一个木偶的流程,我们想要一个做胖木偶的类,还有一个做瘦木偶的类,每个类的方法都差不多,只是具体的实现有所不同,这时我们就可以用模板方法模式,类图如下:
我们在AbstractPerson类中定义了制作玩偶的流程(在createPerson中去调用abstract方法head、body、arms、legs分别去创建玩偶的头、身体、胳膊、腿),而在子类中去做具体的实现,具体实现如下:
public abstract class AbstractPerson {
protected String head;
protected String body;
protected String arms;
protected String legs;
abstract void head();
abstract void body();
abstract void arms();
abstract void legs();
final void createPerson(){
head();
body();
arms();
legs();
System.out.println(head + "," + body + "," + arms + "," + legs + "创建成功!");
}
}
public class FatPerson extends AbstractPerson {
void head() {
head = "大圆脸";
}
void body() {
body = "大肚子";
}
void arms() {
arms = "圆胳膊";
}
void legs() {
legs = "大粗腿";
}
}
public class ThinPerson extends AbstractPerson {
void head() {
head = "瓜子脸";
}
void body() {
body = "A4腰";
}
void arms() {
arms = "细胳膊";
}
void legs() {
legs = "大长腿";
}
}
如上所示,抽象类AbstractPerson类只负责具体的流程指定,而实现类FatPerson和ThinPerson分别对流程进行了具体的实现。
下面进行测试
public class Main {
public static void main(String[] args){
AbstractPerson fatPerson = new FatPerson();
AbstractPerson thinPerson = new ThinPerson();
fatPerson.createPerson();
thinPerson.createPerson();
}
}
结果
那么用模板方法的模式有什么好处呢?
1. 可以在抽象类中定义每个处理的节点,防止遗漏,如果自己实现,不小心某个类忘记了head方法就不好了。
2. 可以让子类只关心具体方法的实现,而不用管这些方法的调用顺序。如果有些方法一定要按照严格的顺序调用,用模板方法实现也是个不错的选择。
3. 调用时引用可以用抽象类,无论父类的对象中保存哪个子类的实例,程序都可以正常运行,这种原则称为里氏替换原则。
模板方法模式属于行为型设计模式,划分了责任和算法
上面简单描述了模板方法模式,接下来我们看一下另外一个和模板方法模式很相似的模式“建造者模式”,何为建造者模式?
建造者模式和模板方法模式略有不同,模板方法模式定义了需要实现的抽象方法,同时也定义了使用这些抽象方法的流程,父类决定了子类的行为。而建造者模式,可以看做是模板方法模式的变种,我们先看一下建造者模式的类图。
为什么说建造者模式是模板方法模式的变种呢?首先上图中的Builder类是一个抽象方法,定义了3个方法,这三个方法在ConcreteBuilder类中实现,Builder类即相当于模板方法中的父类AbstractPerson,与之不同的是,Builder类中只是定义了需要实现的方法,而并没有定义这些方法使用的流程,而是重新抽取了一个新的类Director,这个类聚合了Builder类,同时负责了如何调用Builder中方法的责任。
可以吧Builder类的实现理解为具体的员工,他们会各种技能,但是怎么操作,按照什么样的流程操作,都是由Director(相当于领导)来指挥,这样就可以把具体流程的逻辑封装在Director类中,把“变化”和“不变”解耦。