模板方法模式
模板方法模式
当个别步骤在更详细的层次上的实现可能不同时,将重复的部分采用模板方法模式再次提取到基类来处理。
- 提取子类中更详细层次上的重复代码,不同的定义一个抽象接口(等待子类重写)
- 子类重写不一样的部分
- 客户端代码中声明改成父类,利用多态,实现代码的复用
也就是将重复的地方都可以用接口抽象起来,然后使用继承+多态。使得子类可以自由发挥,定制属于他们不一样的地方,但是重复的地方都在父类中。如果感觉重复代码还是很多,那可以考虑是不是抽象的不够彻底!
C++
/*
碰到这个情况,当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。
我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
*/
#include <iostream>
using namespace std;
class TestPaper
{
public:
void TestQ1()
{
cout << "杨过得到,后来给了郭靖,炼成倚天剑,屠龙刀的玄铁可能是[ ]\na.球磨铸铁 b.马口贴 c.高速合金钢 d.碳素纤维" << endl;
cout << "答案: " << Answer1() << endl;
}
void TestQ2()
{
cout << "杨过、程英、陆无双铲除了情花,造成[ ]\na.使这种植物不再害人 b.使一种珍稀物种灭绝c.破坏了那个生物圈的生态平衡d.造成该地区沙漠化" << endl;
cout << "答案: " << Answer2() << endl;
}
void TestQ3()
{
cout << "蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ]\na.阿司匹林b.牛黄解毒片c.氟哌酸d.让他们喝大量的生牛奶e.以上全不对" << endl;
cout << "答案: " << Answer3() << endl;
}
virtual string Answer1()
{
return "null";
}
virtual string Answer2()
{
return "null";
}
virtual string Answer3()
{
return "null";
}
};
class TestPaperA : public TestPaper
{
string Answer1()
{
return "a";
}
string Answer2()
{
return "b";
}
string Answer3()
{
return "c";
}
};
class TestPaperB : public TestPaper
{
string Answer1()
{
return "a";
}
string Answer2()
{
return "a";
}
string Answer3()
{
return "a";
}
};
int main()
{
cout << "同学A答题情况: " << endl;
TestPaper *A = new TestPaperA();
A->TestQ1();
A->TestQ2();
A->TestQ3();
cout << endl;
cout << "同学B答题情况: " << endl;
TestPaper *B = new TestPaperB();
B->TestQ1();
B->TestQ2();
B->TestQ3();
return 0;
}
C
#include <stdio.h>
#include <string.h>
typedef struct
{
char question[256];
char answer[256];
} Question;
typedef struct
{
Question questions[3];
char *(*getAnswer)(int questionIndex);
} TestPaperBase;
// 定义问题
Question g_questions[3] = {
{"杨过得到,后来给了郭靖,炼成倚天剑,屠龙刀的玄铁可能是[ ]\na.球磨铸铁 b.马口贴 c.高速合金钢 d.碳素纤维", "null"},
{"杨过、程英、陆无双铲除了情花,造成[ ]\na.使这种植物不再害人 b.使一种珍稀物种灭绝c.破坏了那个生物圈的生态平衡d.造成该地区沙漠化", "null"},
{"蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ]\na.阿司匹林b.牛黄解毒片c.氟哌酸d.让他们喝大量的生牛奶e.以上全不对", "null"}
};
char *getAnswerA(int index)
{
switch (index)
{
case 0:
return "a";
case 1:
return "b";
case 2:
return "c";
default:
return "Invalid question index";
}
}
char *getAnswerB(int index)
{
switch (index)
{
case 0:
return "a";
case 1:
return "a";
case 2:
return "a";
default:
return "Invalid question index";
}
}
void TestQ(TestPaperBase *paper, int qIndex)
{
strncpy(paper->questions[qIndex].answer, paper->getAnswer(qIndex), sizeof(paper->questions[qIndex].answer) - 1);
printf("%s\n", paper->questions[qIndex].question);
printf("答案:%s\n", paper->questions[qIndex].answer);
}
int main()
{
TestPaperBase TestPaperA;
memcpy(TestPaperA.questions, g_questions, sizeof(g_questions));
TestPaperA.getAnswer = getAnswerA;
printf("同学A答题情况:\n");
TestQ(&TestPaperA, 0);
TestQ(&TestPaperA, 1);
TestQ(&TestPaperA, 2);
printf("\n");
TestPaperBase TestPaperB;
memcpy(TestPaperB.questions, g_questions, sizeof(g_questions));
TestPaperB.getAnswer = getAnswerB;
printf("同学B答题情况:\n");
TestQ(&TestPaperB, 0);
TestQ(&TestPaperB, 1);
TestQ(&TestPaperB, 2);
return 0;
}
总结
设计基类的时候,最大程度上的去复用代码,尽可能的泛化。细节高层次的差别的地方可以virtual,要求子类重写。