模板方法模式:
通过晚绑定来实现松耦合
在软件构建过程中,对于一个任务,常常有稳定不变的整体结构和流程,但其中某些子步骤存在多变的需求,或者在设计整体结构时,子步骤无法和整体结构同时实现。
比如程序库设计人员提供了MediaProcess
类,用于对媒体码流解复用,和复用
class MediaProcess
{
public:
void demux() {
// 分离音视频
}
void mux() {
// 合并音视频
}
};
作为库的调用者,我的算法是使用库分离视频,对视频解码,做一个对称处理,然后再编码,最后与音频合并
由于我没有处理编解码的方法,于是我自己定义如下class
class Codec
{
public:
bool decode() {
// 解码
}
bool process() {
// 对每一帧进行一个对称处理
}
bool encode() {
// 编码
}
};
于是乎有了以下算法
{
MediaProcess media;
Codec codec;
media.demux();
codec.decode();
codec.process();
codec.encode();
media.mux();
}
- 库的设计者提供了2个步骤
- 程序开发者提供了2,4两个步骤;
程序库肯定比开发人员调用时完成得早得多。面向过程设计中有很多库是这样,设计时只提供这些方法供使用,开发人员自己去实现其他步骤,这样的设计模式是基于早绑定的方式,开发人员不仅需要寻找或者设计其他class,或者方法,并且需要自己来完成这套固化流程。
所以,由于算法的结构时和流程是不变的,库的设计者可以在定义框架的时候就决定整体流程好。在面向对象程序设计中有一种叫做晚绑定的策略。先写好的class通过多态的方式反过来调用晚写好的class。我可以这样重构这个设计
class MediaProcess
{
public:
virtual ~MediaProcess() {}
void run() {
demux();
decode();
process();
encode();
mux();
}
protected:
bool demux() {
// 分离音视频
}
bool mux() {
// 合并音视频
}
virtual bool decode() {
}
virtual bool process() {
}
virtual bool encode() {
}
};
class Application
: public MediaProcess
{
public:
~Application() override {}
bool decode() override {
// 解码为yuv格式
}
bool process() override {
// 对称处理
}
bool encode() override {
// 编码为h264
}
};
于是乎,我们的上面那个算法可以写成:
{
MediaProcess *ptr = new Application;
ptr->run();
delete ptr;
}
- 库的设计者提供了整个流程,如果开发者不重写响应方法就按默认执行(也可设计为纯虚函数成为抽象基类,即接口类,完全让子类来实例化,完成整个流程)
- 程序开发者只需重写需要重写的方法即可;
于是可以得出template method
的含义:定义一个操作中算法的骨架(稳定),将其中一些步骤(变化)延迟到子类(即定义抽象的虚函数,让子类实现)。这样使得子类可以复用算法结构,同时又能重写算法的某些特定步骤。这是一种反向控制的方式。