在前面的文章中我们比较过框架和设计模式,一般的应用程序框架中都会大量用到设计模式。应用程序开发框架允许从一个或一组类中继承以便创建一个新的应用程序,重用现存类中几乎所有的代码,并且覆盖其中一个或多个函数以便自定义所需要的应用程序。
应用程序开发框架中的一个基本的概念是模板方法( Template Method )模式,它是如此的常见以至于我们在使用时甚至不觉得这是个模式,达到了熟视无睹的程度。
模板方法模式的一个重要特征是它(模板方法,这里不是模式名,而是指那个我们称之为模板方法模式的方法或函数)的定义在基类中(有时作为一个保护或私有成员函数)并且不能改动——模板方法模式就是“坚持相同的代码”。它调用其它基类函数(就是那些被派生类覆盖的函数)以便完成其工作,但是客户程序员不必直接调用这些函数。
我们先提供一个简单的例子,然后再到一些常见的应用程序开发框架中找一些现成的例子来给大家参考。
class IUIElement {
protected:
virtual void drawBackground(Painter * painter) = 0;
virtual void drawElement(Painter * painter) = 0;
virtual void drawForeground(Painter * painter) = 0;
public:
void draw(Painter * painter)
{
drawBackground(painter);
drawElement(painter);
drawForeground(painter);
}
};
class CButton : public IUIElement {
protected:
void drawBackground(Painter * painter)
{
//draw background
}
void drawElement(Painter * painter)
{
//draw icon
//draw text
}
void drawForeground(Painter * painter)
{
//draw foreground if necessary
}
};
上面的代码非常简单,我们在日常的开发中经常会实现类似的类,其中 IUIElement 的 draw() 方法就是模板方法,它调用 drawBackground 、 drawElement 、 drawForeground 来完成 element 的绘制。
在我使用过的一些开发框架中,有很多模板方法模式应用的例子,举几个来看看。
先说 Qt ,它是一个完全用 C++ 实现的应用程序框架,目前可以在 Windows 、 Linux 、Android 、iOS、Mac 、塞班等各种平台上使用。QWidget 类是 Qt 中所有可见控件类的基类。它使用了模板方法模式,我们在使用 QWidget 、QLabel 、QListView 等等这些类时,可以重载 paintEvent 、keyPressEvent 等,但是完全不必关心我们重载的这些方法在何处、何时会被调用,而实际上他们是被 QWidget 中的模板方法(比如 render
)调用的。下面是一部分被 QWidget 模板方法调用的可以被我们重载的方法(摘自 Qt 源码):
protected:
// Event handlers
bool event(QEvent *);
virtual void mousePressEvent(QMouseEvent *);
virtual void mouseReleaseEvent(QMouseEvent *);
virtual void mouseDoubleClickEvent(QMouseEvent *);
virtual void mouseMoveEvent(QMouseEvent *);
#ifndef QT_NO_WHEELEVENT
virtual void wheelEvent(QWheelEvent *);
#endif
virtual void keyPressEvent(QKeyEvent *);
virtual void keyReleaseEvent(QKeyEvent *);
virtual void focusInEvent(QFocusEvent *);
virtual void focusOutEvent(QFocusEvent *);
virtual void enterEvent(QEvent *);
virtual void leaveEvent(QEvent *);
virtual void paintEvent(QPaintEvent *);
我最早接触的 UI 框架是 MFC / ATL ,然后是 WTL 。MFC 中也有大量的模板方法模式应用,不再详述,这里要提一下 WTL ,它里面也用到了模板方法模式,而且是很特别的一种实现。
用过 WTL 的开发者都知道这个框架大量使用模板,简直非模板无以 WTL 。我说的 WTL 使用模板方法模式的特别之处就在这里,它通过引入模板,减少了对继承的使用频度(我们知道有个问题叫作“脆弱的基类”问题)。比如 CMDIFrameWindowImpl 这个模板类,实现了 OnSize 方法,通过 MESSAGE_HANDLER 这个宏和 WM_SIZE 消息关联起来,其实 MESSAGE_HANDLER 这个宏已经引入了模板方法,只是我们看不到,有兴趣的可以研究 MFC 的头文件或 ATL
的头文件。特别的地方,我们先看下面的代码然后再回过头来分析。
LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if(wParam != SIZE_MINIMIZED)
{
T* pT = static_cast<T*>(this);
pT->UpdateLayout();
}
// message must be handled, otherwise DefFrameProc would resize the client again
return 0;
}
上面的代码演示的不是模板方法本身,而是被模板方法调用的被派生类覆盖的方法。在 OnSize 中,又通过 static_cast 将 this 指针转换为模板类 T 的指针,调用 T 的 UpdateLayout 方法来应对 SIZE 的变化。这样通过传入不同的 T 就可以在编译时生成不同功能的多文档窗口。我们知道策略模式( Strategy ),是在运行时选择算法,而 WTL 则把模板方法模式和策略模式结合了起来,达到了一种很奇妙的效果:策略实际上是编译时(请理解模板的用法)已经固定下来的,但我们写代码时却有种动态选择的感觉。
来看看 Android 上的应用开发,View 是所有可见控件的基类,如果我们要实现一个自定义的 View ,那么 onDraw 、 onMeasure 、 onLayout 、 onKeyDown 等方法恐怕是要重载的。这里面也是模板方法模式在起作用,可以去看 Android 应用框架的源码。
模板方法模式存在一个基本的问题,就是脆弱的基类问题。比如 MFC ,每次新版本发布后,你都有可能要调整你的程序去适应——因为虽然编译通过,但程序的行为可能因为基类的变化而变得不符合预期。我们说组合优于继承,就和这个问题相关。 java 中有接口( interface ),可以强制派生类实现每一个方法,C++ 中没有接口,但有纯虚函数可以模拟接口,我们要尽可能的使用接口、组合,而不是不假思索的使用继承(实现继承)。
分享到:
相关推荐
设计模式C++学习之模板方法模式(Template Method)
Head First 设计模式 (八) 模板方法模式(Template Method pattern) C++实现
C++设计模式课件3_Template Method_模板方法.pdf
模板方法(TemplateMethod) 用意:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式是一种行为设计模式,它在一个方法中定义算法的骨架,将一些步骤延迟到子类中实现。 具体来说,模板方法模式的关键特点包括: 抽象类:在抽象类中定义一个模板方法,该方法给出了算法的框架。 具体...
C++设计模式代码资源3_Template Method_模板方法.zip
主要为大家详细介绍了C++设计模式之模板方法模式TemplateMethod,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
主要介绍了C++设计模式编程中Template Method模板方法模式的运用,讲到了包括模板方法模式中的细分方法以及适用场景,需要的朋友可以参考下
本文实例讲述了Python设计模式之模板方法模式。分享给大家供大家参考,具体如下: 模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟至子类中.模板方法使得子类可以不改变一个算法的...
设计模式——模板方法模式模板方法模式(Template Method Pattern):定义一个操作中的算法骨架,将一些步骤延迟至子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤使用场景:当不变和可...
c++设计模式-行为型模式-模板方法模式;qt工程;c++简单源码; 模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重...
设计模式(21)-Template Method Pattern 204 一、 模板方法(Template Method)模式 204 二、 模版方法模式的结构 204 三、 模板方法模式的示意性代码 205 四、 继承作为复用的工具 207 五、 一个实际应用模板方法...
C++设计模式笔记(03-02) – Template Method_模板方法(下): https://blog.csdn.net/mofan6930/article/details/104383750 参考书籍:《设计模式:可复用面向对象软件的基础》 参考课程:《C++设计模式》-李建忠 ...
整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法可以作为后来者的榜样。如果要知道怎样恰当定义和描述设计模式,我们应该可以从他们那儿获得启发”--steve...
第16章 按部就班:模板方法模式 (TemplateMethod) 第17章 风吹草动:观察者模式 (Observer) 第18章 变化多端:状态模式 (State) 第19章 明修栈道,暗度陈仓:策略模式 (Strategy) 第20章 循序渐进:职责链模式 ...
设计模式(21)-Template Method Pattern 一、 模板方法(Template Method)模式 二、 模版方法模式的结构 三、 模板方法模式的示意性代码 四、 继承作为复用的工具 五、 一个实际应用模板方法的例子 六、 ...
工厂方法模式(Factory Method) 5. 原型模式(Prototype)结构型: 6. 适配器模式(Adapter Pattern) 7. 桥接模式(Bridge Pattern) 8. 装饰模式(Decorator Pattern) 9. 组合模式(Composite Pattern) 10. 外观模式...
23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。另外附上“设计模式迷你手册.chm” 供参考。 注:项目在 VS2008 下...模板方法模式(Template Method) 访问者模式(Visitor)
模板方法模式[TEMPLATE METHOD PATTERN] 建造者模式[BUILDER PATTERN] 策略模式 代理模式 单例模式 多例模式 工厂方法模式 抽象工厂模式 门面模式 适配器模式 模板方法模式 建造者模式 桥梁模式 命令模式 装饰模式 ...