【设计模式】考题 -- 模板方法模式
一,概述
模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构既可以重定义该算法的某些特定步骤
核心思想:抽象类的方法推迟到子类实现。基类示例指向子类实现
二,示例
老师出考题,学生抄题,然后答题。
1)第一种实现方式
缺点:学生每次都要抄题,而且每个学生类都要重复同样的代码。容易抄错题、难更改。
#include <iostream> using namespace std; //学生甲抄的试卷 class TestPaperA { public: //试题1 void TestQuestion1() { cout<<" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 "<<endl; cout<<"答案:b"<<endl; } //试题2 void TestQuestion2() { cout<<" 杨过、程英、陆无双铲除了情花,造成[ ] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化 "<<endl; cout<<"答案:a"<<endl; } //试题3 void TestQuestion3() { cout<<" 蓝凤凰的致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对 "<<endl; cout<<"答案:c"<<endl; } }; //学生乙抄的试卷 class TestPaperB { public: //试题1 void TestQuestion1() { cout<<" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 "<<endl; cout<<"答案:d"<<endl; } //试题2 void TestQuestion2() { cout<<" 杨过、程英、陆无双铲除了情花,造成[ ] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化 "<<endl; cout<<"答案:b"<<endl; } //试题3 void TestQuestion3() { cout<<" 蓝凤凰的致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对 "<<endl; cout<<"答案:a"<<endl; } }; int main() { cout<<"学生甲抄的试卷:"<<endl; TestPaperA *studentA = new TestPaperA(); studentA->TestQuestion1(); studentA->TestQuestion2(); studentA->TestQuestion3(); cout<<"学生乙抄的试卷:"<<endl; TestPaperB *studentB = new TestPaperB(); studentB->TestQuestion1(); studentB->TestQuestion2(); studentB->TestQuestion3(); }
2)提炼之后的代码
改进之处:让老师印制多份试卷,避免让同学抄卷子出错。(不用每个同学都抄题)
让试卷为基类,学生只需要继承,然后将试题显示,然后标注答案就可以。
#include <iostream> using namespace std; //金庸小说考题试卷 class TestPaper { public: //试题1 void TestQuestion1() { cout<<" 1)杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 "<<endl; } //试题2 void TestQuestion2() { cout<<" 2)杨过、程英、陆无双铲除了情花,造成[ ] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化 "<<endl; } //试题3 void TestQuestion3() { cout<<"3) 蓝凤凰的致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对 "<<endl; } }; class TestPaperA : 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 : TestPaper { public: void TestQuestion1() { TestPaper::TestQuestion1(); cout<<"答案:b"<<endl; } void TestQuestion2() { TestPaper::TestQuestion2(); cout<<"答案:b"<<endl; } void TestQuestion3() { TestPaper::TestQuestion3(); cout<<"答案:b"<<endl; } }; int main() { cout<<"学生甲抄的试卷:"<<endl; TestPaperA *studentA = new TestPaperA(); studentA->TestQuestion1(); studentA->TestQuestion2(); studentA->TestQuestion3(); cout<<"学生乙抄的试卷:"<<endl; TestPaperB *studentB = new TestPaperB(); studentB->TestQuestion1(); studentB->TestQuestion2(); studentB->TestQuestion3(); }
3)利用模板方法模式
改进:深度泛化。其实每个学生真正的不同之处就是,答案不同,所以只需要学生提供答案就可以。而试题和填写答案的方法就写到抽象类里。
重点:TestPaper *studentA = new TestPaperA(); //父类对象 用子类实现
studentA->TestQuestion1(); //父类对象调用,所用到的虚函数调用子类已经实现好的
#include <iostream> using namespace std; class TestPaper { public: void TestQuestion1() { cout<<" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 "<<endl; cout<<"答案:" + Answer1()<<endl; } void TestQuestion2() { cout<<" 杨过、程英、陆无双铲除了情花,造成[ ] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化 "<<endl; cout<<"答案:" + Answer2()<<endl; } void TestQuestion3() { cout<<" 蓝凤凰的致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对 "<<endl; cout<<"答案:" + Answer3()<<endl; } protected: virtual string Answer1() { return ""; } virtual string Answer2() { return ""; } virtual string Answer3() { return ""; } }; //学生甲抄的试卷 class TestPaperA : public TestPaper { protected: string Answer1() { return "b"; } string Answer2() { return "c"; } string Answer3() { return "a"; } }; //学生乙抄的试卷 class TestPaperB :public TestPaper { protected: string Answer1() { return "c"; } string Answer2() { return "a"; } string Answer3() { return "a"; } }; int main() { cout<<"学生甲抄的试卷:"<<endl; TestPaper *studentA = new TestPaperA(); studentA->TestQuestion1(); studentA->TestQuestion2(); studentA->TestQuestion3(); cout<<"学生乙抄的试卷:"<<endl; TestPaper *studentB = new TestPaperB(); studentB->TestQuestion1(); studentB->TestQuestion2(); studentB->TestQuestion3(); }
三,通用范例(C#)
class Program { static void Main(string[] args) { AbstractClass c; c = new ConcreteClassA(); c.TemplateMethod(); c = new ConcreteClassB(); c.TemplateMethod(); Console.Read(); } } abstract class AbstractClass { public abstract void PrimitiveOperation1(); public abstract void PrimitiveOperation2(); public void TemplateMethod() { PrimitiveOperation1(); PrimitiveOperation2(); Console.WriteLine(""); } } class ConcreteClassA : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("具体类A方法1实现"); } public override void PrimitiveOperation2() { Console.WriteLine("具体类A方法2实现"); } } class ConcreteClassB : AbstractClass { public override void PrimitiveOperation1() { Console.WriteLine("具体类B方法1实现"); } public override void PrimitiveOperation2() { Console.WriteLine("具体类B方法2实现"); } }