C#面向对象设计模式纵横谈:Template Method 模板方法
无处不在的Template Method
如果你只想掌握一种设计模式,那么它就是
-----Template Method!
变与不变
变化——是软件设计的永恒主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何分析,并发现系统中的变化点和稳定点,并使用特定的设计方法来应对这种变化。
动机(Motivation)
在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
意图(Intent)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
——《设计模式》GoF
例说Template Method应用
下面是汽车测试软件的例子
具体实现
客户程序
这里new的地方可以根据需要用创建型的设计模式来设计。
这里我们把抽象类里面的抽象方法写为了public,我建议对于虚方法或者抽象方法,一般写为protected;对于非虚的方法或者非抽象的方法,才写为public。因为如果是公有的虚方法,它就担当了两个不同方面的责任。只要设置了一个虚方法,那就意味着这是一个扩展点。如果是public方法,也就是客户程序可以直接访问这个函数,但是虚方法是不具有外界访问的资质的。因此我们推荐虚方法都用protected来修饰。
结构(Structure)
AbstractClass对应例子中的Vehicle抽象类,TemplateMethod对应例子中的Test方法,PrimitiveOperation等虚方法对应Startup、Run等虚方法,ConcreteClass对应HongqiCar具体类。
Template Method模式的几个要点
Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展,是代码复用方面的基本实现结构。除了可以灵活应对子步骤的变化外,“Don't call me, let me call you(不要调用我,让我来调用你)”的反向控制结构是Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。
.NET架构中的Template Method应用
一个简单的Windows窗体应用
这里OnPaint是一个虚方法的子步骤,这就是一个Template Method设计模式。如果我们不去重写这个OnPaint方法,它就有一个基本的默认实现,画一个空窗体。这里我们并没有调用OnPaint方法,而是Application的Run会进入Windows的消息循环结构,Paint就是一个消息。当我们移动一下窗口都会导致Paint事件的发生,并导致OnPaint函数的调用,这就是一种反向调用。当然,还有很多其他的子步骤可以提供扩展点,例如OnClose等,很多以On开头的全部都是Template Method模式的虚方法。
这个里面内容很复杂,它并不是用一个Template Method在里面调用所有的子步骤方法,它实际上是把整体的Template Method方法置于了一个消息循环的结构里面,我们可以把消息循环的结构看做模板方法里面的TemplateMethod公有非虚方法。