【设计模式系列】行为型模式之Template Method模式
概要
Template Method模式,这里的Template跟C++或java的模板是两回事,只是表达含义的模式名而已。从名字来理解,Template Method模式就是一种把处理模板化的模式。详细来说,Template Method模式会把一些比较稳定的算法封装到抽象层的基类方法中,在Template Method中通过多态去调用一些子类的具体实现。
目的
在基类中定义算法框架的方法,通过该方法去调用子类中封装的算法各个步骤的具体实现。
实例
设计一个绘图程序,会根据实际情况使用多个第三方库绘制直线的方法,在我们的程序中要实现矩形绘制的方法。
分析一下这个绘图程序的需求,首先会有多个库提供绘制直线的方法,那么这里可以进行抽象化,我们需要这样一个基类Draw,第三方库都可以从Draw类继承:
class Draw { public: virtual void DrawLine(const Point& x, const Point& y) = 0; }; class DrawLib1 : public Draw { public: virtual void DrawLine(const Point& x, const Point& y) { // drawing line by lib1 from point x to point y } }; class DrawLib2 : public Draw { public: virtual void DrawLine(const Point& x, const Point& y) { // drawing line by lib2 from point x to point y } };
其次,我们需要画矩形,画矩形其实就 包含了一种算法,而且是一种常识性不会发生变化的算法,我们就把这种算法封装到D基类Draw中:
class Draw { public: void DrawSquare(const Point& s1, const Point& s2, const Point& s3, const Point& s4) { DrawLine(s1, s2); DrawLine(s2, s3); DrawLine(s3, s4); DrawLine(s4, s1); } virtual void DrawLine(const Point& x, const Point& y) = 0; };
类图如下:
OK, 其实到这里我们就已经基于Template Method模式的基本思想实现了我们的需求。再总结一下吧,
1. 我们把稳定的画矩形算法封装到了基类中
2. 在子类中,我们实现了画矩形算法中各个画边步骤的具体实现
3. 在基类封装的算法方法中通过多态调用了子类的画线的具体实现
应用
如果有人看过我的关于Strategy模式的文章,也许会疑惑:上面的例子不是Strategy模式中举的反例吗,怎么就变成Template Method模式了?解释下:
首先,模式本身没有优劣,只是基于不同情况不同应用场合应该选择更合适的设计模式。
其次,Strategy和Template Method模式其实真的很相似,Strategy模式是把算法抽出来,封装到另外单独的类中,而Template Method模式则是把算法封装在基类中。不存在哪种更好,因为各有特点,选择因场合而异。
第三,说说两种模式各自的特点,以及我们如何选择吧。Template Method模式中,封装的算法一般都很稳定,不容易发生变更,所以放在同样相对比较稳定的抽象层,而且处理相对简单,方法比较单一,所以没有必要去单独创建一个类来封装算法。而Strategy模式中,算法可以跟外部有一定耦合,有时会发生一些变更,同时支持运行时切换子类中的具体实现。关于运行时切换,不理解的可以参照Strategy模式的文章:
最后有一点注意了,如果用Template Method模式的话,封装的Template Method也就是上例中的DrawSquare方法,不能被重写(override),要不就违背了Template Method模式的基本思想。