设计模式(十五)——模板方法模式
一、模板方法模式简介
1、模板方法模式简介
模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。
模板方法模式的关键是将通用算法(逻辑)封装在抽象基类中,并将不同的算法细节放到子类中实现。
模板方法模式是通过把不变行为搬移到基类,去除之类中的重复代码来体现优势。
当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。通过模板方法模式把不变的行为搬移到单一的地方,帮助子类摆脱重复的不变行为的纠缠。
2、模板方法模式角色
AbstractClass抽象类:是一个抽象模板,定义并实现了一个模板方法。模板方法一般是一个具体方法,给出了一个顶层逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到之类实现。顶层逻辑也有可能调用一些具体方法。
ConcreteClass具体类:实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一ConcreteClass都可以给出抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
3、模板方法模式优缺点
模板方法模式的优点:
A、模板方法模式在一个类中形式化地定义算法,而由子类实现细节的处理。
B、模板方法是一种代码复用的基本技术。模板方法在类库中尤为重要,提取了类库中的公共行为。
C、模板方法模式导致一种反向的控制结构,通过一个父类调用其子类的操作(而不是相反的子类调用父类),通过对子类的扩展增加新的行为,符合“开闭原则”
模板方法模式的缺点:
每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。
4、模板方法模式使用场景
模板方法模式使用场景:
A、一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
B、各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。在一个调用新的操作的模板方法来替换不同的代码。
C、控制子类扩展。模板方法只在特定点调用“ hook”操作 ,因此只允许在特定点进行扩展。
二、模板方法模式实现
AbstractClass抽象模板类:
#ifndef ABSTRACTCLASS_H #define ABSTRACTCLASS_H #includeusing namespace std; //抽象模板 class AbstractClass { public: //模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,推迟到子类中实现 void templateMethod() { operationOne(); operationTwo(); } //一些抽象行为,放到子类中去实现 virtual void operationOne() = 0; virtual void operationTwo() = 0; protected: AbstractClass(){} }; #endif // ABSTRACTCLASS_H
ConcreteClassA具体实现类:
#ifndef CONCRETECLASSA_H #define CONCRETECLASSA_H #include "AbstractClass.h" //实现基类所定义的抽象方法 class ConcreteClassA : public AbstractClass { public: ConcreteClassA(){} //实现基类定义的抽象行为 void operationOne() { cout << "ConcreteClassA::operationOne" << endl; } void operationTwo() { cout << "ConcreteClassA::operationTwo" << endl; } }; #endif // CONCRETECLASSA_H
ConcreteClassB具体实现类:
#ifndef CONCRETECLASSB_H #define CONCRETECLASSB_H #include "AbstractClass.h" //实现基类所定义的抽象方法 class ConcreteClassB : public AbstractClass { public: ConcreteClassB(){} //实现基类定义的抽象行为 void operationOne() { cout << "ConcreteClassB::operationOne" << endl; } void operationTwo() { cout << "ConcreteClassB::operationTwo" << endl; } }; #endif // CONCRETECLASSB_H
客户调用程序:
#include "AbstractClass.h" #include "ConcreteClassA.h" #include "ConcreteClassB.h" int main() { AbstractClass* a = new ConcreteClassA(); a->templateMethod(); AbstractClass* b = new ConcreteClassB(); b->templateMethod(); delete a, b; return 0; }
三、模板方法模式实例
银行业务办理流程实例:
在银行办理业务时,一般都包含几个基本固定步骤:取号排队->办理具体业务->对银行工作人员进行评分。取号取号排队和对银行工作人员进行评分的业务逻辑是一样的。办理具体业务是不相同的,具体业务可能取款、存款或者转账。
BankBusiness抽象类:
#ifndef BANKBUSINESS_H #define BANKBUSINESS_H #includeusing namespace std; //银行业务抽象类 class BankBusiness { public: unsigned int takeNumber() { return ++m_number; } bool isEvaluateHook() { return true; } void evaluateHook() { cout << "satisfactory" << endl; } //模板方法,银行业务办理流程 void progress() { takeNumber();//取号 transact();//业务办理 if(isEvaluateHook())//是否评价 evaluateHook();//评价操作 } //业务办理接口 virtual void transact() = 0; protected: BankBusiness(){}//不开放接口 private: unsigned int m_number; }; #endif // BANKBUSINESS_H
Deposit存款具体子类:
#ifndef DEPOSIT_H #define DEPOSIT_H #include "BankBusiness.h" //存款类业务 class Deposit : public BankBusiness { public: void transact() { cout << "Deposit" << endl; } }; #endif // DEPOSIT_H
Transfer转账具体子类:
#ifndef TRANSFER_H #define TRANSFER_H #include "BankBusiness.h" //转账类业务 class Transfer : public BankBusiness { public: void transact() { cout << "Transfer" << endl; } }; #endif // TRANSFER_H
Withdraw取款具体子类:
#ifndef WITHDRAW_H #define WITHDRAW_H #include "BankBusiness.h" //取款类业务 class Withdraw : public BankBusiness { public: void transact() { cout << "Withdraw" << endl; } }; #endif // WITHDRAW_H
客户调用程序:
#include "BankBusiness.h" #include "Deposit.h" #include "Transfer.h" #include "Withdraw.h" int main() { //办理取款业务的流程 BankBusiness* deposit = new Deposit(); deposit->progress(); //办理转账业务的流程 BankBusiness* transfer = new Transfer(); transfer->progress(); delete deposit,transfer; return 0; }