当一个算法分成很多步骤时,其中有些步骤是固定不变的,有些步骤是会变化的。那么一般的想法是直接把每一步都作为一个方法写出来,然后在主方法中调用:
class Steps {
void func0() {
// 具体实现
}
void func1() {
// 具体实现
}
void func2() {
// 具体实现
}
void func3() {
// 具体实现
}
void func4() {
// 具体实现
}
}
class Structure{
void run() {
Steps steps = new Steps();
//真实的流程可能不是顺序结构
steps.func0();
steps.func1();
steps.func2();
steps.func3();
steps.func4();
}
}
这种做法的不足是当其中一个步骤变了,那么就要再新建一个Steps1类,Steps1中所有的方法都要重新编译过。而且主函数中也要重新生成该类的对象。这样没有实现代码的复用,这里的复用不单指不用重写代码,而是指运行时的复用,不用编译新的类,直接复用旧的类。但就算一个类中有一行代码的改变,这个类就要被重新编译,不算复用了。而设计模式的目的在于提高代码的运行编译复用。
为了改进这种方法,就有第二种做法,将经常变化的几个步骤放到另一个类中:
class StaticSteps {
void func0() {
// 具体实现
}
void func1() {
// 具体实现
}
void func2() {
// 具体实现
}
}
class DynamicSteps{
void func3() {
// 具体实现
}
void func4() {
// 具体实现
}
}
class Structure{
void run() {
StaticSteps SSteps = new StaticSteps();
DynamicSteps DSteps=new DynamicSteps();
SSteps.func0();
SSteps.func1();
SSteps.func2();
DSteps.func3();
DSteps.func4();
}
}
这种做法变化的部分提取了出来,但是根据开闭原则,当哪个步骤有变化时,是要生成新的DynamicSteps1类,而不是在已有的DynamicSteps类上改动,那么当有哪个步骤需要更改时,主函数就需要生成新的类的对象,那么主函数就要变了,但是我们知道一个算法的主要流程架构是属于稳定部分,不能轻易改动。于是再改进,它的目的是不改动主函数:
abstract class StaticSteps {
void func0() {
// 具体实现
}
void func1() {
// 具体实现
}
void func2() {
// 具体实现
}
abstract void func3();
abstract void func4();
}
//将变化的部分延迟到子类实现
class DynamicSteps extends StaticSteps{
@Override
void func3() {
// 具体实现
}
@Override
void func4() {
// 具体实现
}
}
class Structure{
void run(StaticSteps sSteps) {//子类通过向上转换传到这
StaticSteps SSteps = sSteps;
SSteps.func0();
SSteps.func1();
SSteps.func2();
//函数体中因为多态其实调用的是子类具体实现函数
SSteps.func3();
SSteps.func4();
}
}
这样当其中几步改变时,以上代码是不会变的,我们需要改变的是新增一个类实现更改的步骤,在调用run函数时实参传递的是新增的类。这就是Template Method模式,模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现。