上篇文章,介绍了《大话设计模式》的第9章——原型模式。
本篇,来介绍《大话设计模式》的第10章——模板方法。并通过C++代码实现实例代码的功能。
1 模板方法
模板方法模式(TemplateMethod):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2 实例
背景:书中小故事,抄题目做题,看不清黑板,题目抄错,导致做题肯定是错的。
题目:用代码的形式来实现。
2.1 版本一:单独的试卷类
版本一的实现比较简单,学生甲和学生乙单独抄试卷做题,分别实现两个类。
2.1.1 两个同学分别抄题目作答
定义两个类,实现两个同学独自抄题做题:
// 学生甲抄的试卷
class TestPaperA
{
public:
// 试题1
void TestQuestion1()
{
printf("1.在TCP/IP协议栈中,应用层协议数据单元为(). A.消息 B.段 C.用户数据报 D.帧\n");
printf("答案: B\n");
}
// 试题2
void TestQuestion2()
{
printf("2.在C语言中,char型数据在内存中的存储形式是(). A.补码 B.反码 C.原码 D.ASCII码\n");
printf("答案: D\n");
}
// 试题3
void TestQuestion3()
{
printf("3.某计算机字长是32位,存储容量是256KB, 按字编址的寻址范围是(). A.128K B.64K C.32K D.16K\n");
printf("答案: B\n");
}
};
// 学生乙抄的试卷
class TestPaperB
{
public:
// 试题1
void TestQuestion1()
{
printf("1.在TCP/IP协议栈中,应用层协议数据单元为(). A.消息 B.段 C.用户数据报 D.帧\n");
printf("答案: B\n");
}
// 试题2
void TestQuestion2()
{
printf("2.在C语言中,char型数据在内存中的存储形式是(). A.补码 B.反码 C.原码 D.ASCII码\n");
printf("答案: B\n");
}
// 试题3
void TestQuestion3()
{
printf("3.某计算机字长是32位,存储容量是256KB, 按字编址的寻址范围是(). A.128K B.64K C.32K D.16K\n");
printf("答案: C\n");
}
};
2.1.2 主函数
首先,实例化两个同学,抄题做题,
然后,就可以调用展示接口来显示出来了。
int main()
{
printf("学生甲抄的试卷:\n");
TestPaperA studentA;
studentA.TestQuestion1();
studentA.TestQuestion2();
studentA.TestQuestion3();
printf("\n学生乙抄的试卷:\n");
TestPaperB studentB;
studentB.TestQuestion1();
studentB.TestQuestion2();
studentB.TestQuestion3();
return 0;
}
代码运行效果如下:
下面来看版本二。
2.2 版本二:对试卷题目封装为一个类
版本二,是将题目封装为一个类,这样就确保两个同学做的题目是一样的:
2.2.1 试题类
// 计算机试题
class TestPaper
{
public:
// 试题1
void TestQuestion1()
{
printf("1.在TCP/IP协议栈中,应用层协议数据单元为(). A.消息 B.段 C.用户数据报 D.帧\n");
}
// 试题2
void TestQuestion2()
{
printf("2.在C语言中,char型数据在内存中的存储形式是(). A.补码 B.反码 C.原码 D.ASCII码\n");
}
// 试题3
void TestQuestion3()
{
printf("3.某计算机字长是32位,存储容量是256KB, 按字编址的寻址范围是(). A.128K B.64K C.32K D.16K\n");
}
};
2.2.2 两个同学分别作答
定义的两个同学类,继承题目类,然后仅根据题目作答即可。
// 学生甲抄的试卷
class TestPaperA : public TestPaper
{
public:
// 试题1
void TestQuestion1()
{
TestPaper::TestQuestion1();
printf("答案: B\n");
}
// 试题2
void TestQuestion2()
{
TestPaper::TestQuestion2();
printf("答案: D\n");
}
// 试题3
void TestQuestion3()
{
TestPaper::TestQuestion3();
printf("答案: B\n");
}
};
// 学生乙抄的试卷
class TestPaperB : public TestPaper
{
public:
// 试题1
void TestQuestion1()
{
TestPaper::TestQuestion1();
printf("答案: B\n");
}
// 试题2
void TestQuestion2()
{
TestPaper::TestQuestion2();
printf("答案: B\n");
}
// 试题3
void TestQuestion3()
{
TestPaper::TestQuestion3();
printf("答案: C\n");
}
};
2.2.3 主函数
主函数不用改。
代码运行效果如下:
2.3 版本三:模板方法模式
版本三,模板方法模式。在版本二中,每个同学的类中,还需要有重复的printf(“答案: X\n”);这类代码,实际上,每个同学作答不一样的地方,只是ABCD的这4个选项。
因此,可以将重复的printf也提升到试卷类中,并对ABCD的这4个选项的选择提供一个虚方法,在运行时由子类(同学类)来实现:
2.3.1 试题类
// 计算机试题
class TestPaper
{
public:
// 试题1
void TestQuestion1()
{
printf("1.在TCP/IP协议栈中,应用层协议数据单元为(). A.消息 B.段 C.用户数据报 D.帧\n");
printf("答案: %s\n", Answer1().c_str());
}
// 试题2
void TestQuestion2()
{
printf("2.在C语言中,char型数据在内存中的存储形式是(). A.补码 B.反码 C.原码 D.ASCII码\n");
printf("答案: %s\n", Answer2().c_str());
}
// 试题3
void TestQuestion3()
{
printf("3.某计算机字长是32位,存储容量是256KB, 按字编址的寻址范围是(). A.128K B.64K C.32K D.16K\n");
printf("答案: %s\n", Answer3().c_str());
}
protected:
virtual std::string Answer1() {return "";};
virtual std::string Answer2() {return "";};
virtual std::string Answer3() {return "";};
};
2.3.2 两个同学分别作答
// 学生甲抄的试卷
class TestPaperA : public TestPaper
{
protected:
// 试题1
std::string Answer1() {return "B";};
// 试题2
std::string Answer2() {return "D";};
// 试题3
std::string Answer3() {return "B";};
};
// 学生乙抄的试卷
class TestPaperB : public TestPaper
{
protected:
// 试题1
std::string Answer1() {return "B";};
// 试题2
std::string Answer2() {return "B";};
// 试题3
std::string Answer3() {return "C";};
};
2.3.3 主函数
主函数不用改。
代码运行效果如下:
总结
本篇介绍了设计模式中的模板方法模式,并通过学生抄写题目作答的实例,使用C++编程,来演示模板方法模式的使用。