模板方法模式
理论
模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
AbstractClass是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
class AbstractClass{ public: //一些抽象行为,放到子类去实现 virtual void PrimitiveOperation1() {}; virtual void PrimitiveOperation2() {}; //模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,它们都推迟到子类实现 void TemplateMethod(){ PrimitiveOperation1(); PrimitiveOperation2(); } };
ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个 AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
模板方法模式特点
模板方法模式是通过把不变的行为搬移到父类,去除子类中的重复代码来体现它的优势。相当于提供了一个很好的代码复用平台。
应用场景
当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们就可以通过模板方法模式把这些行为搬移到单一的地方,这样就可以帮助子类摆脱重复的不变行为的纠缠。
实例
数学老师的随堂测验,老师在黑板上抄题目,要求学生先抄题目,然后再做答案。写出抄题目的程序。
初步实现
#include <iostream> using namespace std; //考题试卷 class TestPaper { public: void TestQuestion1() { cout << "1 + 1 = [] a.1 b.2 c.3 d.4" << endl; } void TestQuestion2() { cout << "1 + 2 = [] a.1 b.2 c.3 d.4" << endl; } void TestQuestion3() { cout << "1 + 3 = [] a.1 b.2 c.3 d.4" << endl; } }; //学生甲抄的试卷 class TestPaperA : public TestPaper { public: void TestQuestion1() { TestPaper::TestQuestion1(); cout << "答案:b" << endl; } void TestQuestion2() { TestPaper::TestQuestion2(); cout << "答案:b" << endl; } void TestQuestion3() { TestPaper::TestQuestion3(); cout << "答案:b" << endl; } }; //学生乙抄的试卷 class TestPaperB : public TestPaper { public: void TestQuestion1() { TestPaper::TestQuestion1(); cout << "答案:a" << endl; } void TestQuestion2() { TestPaper::TestQuestion2(); cout << "答案:a" << endl; } void TestQuestion3() { TestPaper::TestQuestion3(); cout << "答案:a" << endl; } }; //客户端 int main() { cout << "学生甲抄的试卷:" << endl; TestPaperA* studentA = new TestPaperA(); studentA->TestQuestion1(); studentA->TestQuestion2(); studentA->TestQuestion3(); cout << "------------------------" << endl; cout << "学生乙抄的试卷:" << endl; TestPaperB* studentB = new TestPaperB(); studentB->TestQuestion1(); studentB->TestQuestion2(); studentB->TestQuestion3(); delete studentA; delete studentB; system("pause"); return 0; }
虽然用了继承,但是两个学生类里面仍然有雷士的代码。除了所选答案“a”和“b”,其他的都是重复的。
当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
模板方法模式
UML类图
代码实现
#include <iostream> using namespace std; //考题试卷 class TestPaper { public: void TestQuestion1() { cout << "1 + 1 = [] a.1 b.2 c.3 d.4" << endl; cout << "答案:" << Answer1() << endl; //改成一个虚方法 } void TestQuestion2() { cout << "1 + 2 = [] a.1 b.2 c.3 d.4" << endl; cout << "答案:" << Answer2() << endl; } void TestQuestion3() { cout << "1 + 3 = [] a.1 b.2 c.3 d.4" << endl; cout << "答案:" << Answer3() << endl; } protected: //此方法的目的就是给继承的子类重写,因为这里每一个人的答案都是不同的 virtual string Answer1() { return ""; } virtual string Answer2() { return ""; } virtual string Answer3() { return ""; } }; //学生甲抄的试卷 class TestPaperA : public TestPaper { public: string Answer1() { return "a"; } string Answer2() { return "a"; } string Answer3() { return "a"; } }; //学生乙抄的试卷 class TestPaperB : public TestPaper { public: string Answer1() { return "b"; } string Answer2() { return "b"; } string Answer3() { return "b"; } }; //客户端 int main() { cout << "学生甲抄的试卷:" << endl; TestPaper* studentA = new TestPaperA(); //将子类变量的声明改成了父类,利用了多态性,实现了代码的复用 studentA->TestQuestion1(); studentA->TestQuestion2(); studentA->TestQuestion3(); cout << "------------------------" << endl; cout << "学生乙抄的试卷:" << endl; TestPaper* studentB = new TestPaperB(); studentB->TestQuestion1(); studentB->TestQuestion2(); studentB->TestQuestion3(); delete studentA; delete studentB; system("pause"); return 0; }