基本概念
模板方法模式是一种行为设计模式, 它在超类(基类)中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
该模式是对于面向过程编程的一种抽象,它定义了一个算法的骨架,将一些步骤的实现延迟到子类。子类在不改变算法结构的情况下,重新定义算法的某些步骤。
比如,做一道菜至少需要三步:
- 准备食材
- 烹饪
- 上菜
虽然不同菜品的烹饪方法和准备过程不同,但是不妨碍我们定义一个算法的“骨架”,包含这三个步骤,然后将烹饪过程放到具体的炒菜类去实现,这样无论是吵什么才,都可以亚勇相同的炒菜算法,只需要在子类中实现具体的炒菜步骤就行。模板方法模式提高了代码的可复用性,类似于模板编程。
基本结构
在原来的若干类的基础上,抽象出一个模板方法,定义一个模板抽象类,然后具体类继承自模板类,实现了模板类中定义的抽象方法,去完成算法中的特定步骤。
- 模板类
AbstractClass
:由一个模板方法和若干个基本方法构成,模板方法定义了逻辑的骨架,按照顺序去调用包含的基本方法,基本方法同时是一些抽象方法,这些方法由子类去实现。基本方法还包含一些具体方法,他们是算法类的一部分但已经有默认实现,在具体子类可以继承或者重写。 - 具体类
ConcreteClass
:继承自模板类,实现了模板类中定义的抽象方法,完成算法中特定步骤的具体实现。
class AbstractClass {/*** The template method defines the skeleton of an algorithm.*/public:void TemplateMethod() const {this->BaseOperation1();this->RequiredOperations1();this->BaseOperation2();this->Hook1();this->RequiredOperation2();this->BaseOperation3();this->Hook2();}/*** These operations already have implementations.*/protected:void BaseOperation1() const {std::cout << "AbstractClass says: I am doing the bulk of the work\n";}void BaseOperation2() const {std::cout << "AbstractClass says: But I let subclasses override some operations\n";}void BaseOperation3() const {std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n";}/*** These operations have to be implemented in subclasses.*/virtual void RequiredOperations1() const = 0;virtual void RequiredOperation2() const = 0;/*** These are "hooks." Subclasses may override them, but it's not mandatory* since the hooks already have default (but empty) implementation. Hooks* provide additional extension points in some crucial places of the* algorithm.*/virtual void Hook1() const {}virtual void Hook2() const {}
};
/*** Concrete classes have to implement all abstract operations of the base class.* They can also override some operations with a default implementation.*/
class ConcreteClass1 : public AbstractClass {protected:void RequiredOperations1() const override {std::cout << "ConcreteClass1 says: Implemented Operation1\n";}void RequiredOperation2() const override {std::cout << "ConcreteClass1 says: Implemented Operation2\n";}
};
/*** Usually, concrete classes override only a fraction of base class' operations.*/
class ConcreteClass2 : public AbstractClass {protected:void RequiredOperations1() const override {std::cout << "ConcreteClass2 says: Implemented Operation1\n";}void RequiredOperation2() const override {std::cout << "ConcreteClass2 says: Implemented Operation2\n";}void Hook1() const override {std::cout << "ConcreteClass2 says: Overridden Hook1\n";}
};
/*** The client code calls the template method to execute the algorithm. Client* code does not have to know the concrete class of an object it works with, as* long as it works with objects through the interface of their base class.*/
void ClientCode(AbstractClass *class_) {// ...class_->TemplateMethod();// ...
}int main() {std::cout << "Same client code can work with different subclasses:\n";ConcreteClass1 *concreteClass1 = new ConcreteClass1;ClientCode(concreteClass1);std::cout << "\n";std::cout << "Same client code can work with different subclasses:\n";ConcreteClass2 *concreteClass2 = new ConcreteClass2;ClientCode(concreteClass2);delete concreteClass1;delete concreteClass2;return 0;
}
Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anywaySame client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
上述代码源自该C++ 模板方法模式讲解和代码示例,我们来分析一下这个代码的含义。
首先是定义了一个抽象类,定义了公有方法TemplateMethod
,按照一定的顺序把所有的类方法都执行一遍。并提供了两个公有函数BaseOperation1
和BaseOperation2
,然后在保护域中定义了四个虚函数,RequireOperation1
和RequireOperation2
是纯虚函数,子类必须实现,还有两个Hook1
和Hook2
是提供了默认的空操作,子类可以选择自己实现。
然后在客户端直接去调用公有方法TemplateMethod
,不同的子类的实现方式略有区别,子类1只实现了必要的操作,而子类2还实现了Hook1
,即模板方法模式在已有的算法骨架下支持一定的拓展。
综上所述,模板方法模式适用于程式固化的模块,抽象出一个算法“骨架”这样可以方便统一管理,也支持一定的拓展。