前言
在遇到重复代码比较多时,使用继承来将重复的代码集中到父类中,子类只需要完成自己的逻辑,是一个不错的方法。
模板模式
模板模式可以概括为:当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板的方法模式来处理。
例如,我们写一个做试卷的类,根据不同的考题做出作出不同的答案。
#include "Include.h"
class TestPaper1{
public:
void Question1(){
printf("倚天屠龙剑的玄铁可能是:\n");
printf("a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维\n");
printf("答案:b\n");
}
void Question2(){
printf("杨过,程英,陆无双铲除了情花,造成:\n");
printf("a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化\n");
printf("答案:a\n");
}
};
class TestPaper2{
public:
void Question1(){
printf("倚天屠龙剑的玄铁可能是:\n");
printf("a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维\n");
printf("答案:d\n");
}
void Question2(){
printf("杨过,程英,陆无双铲除了情花,造成:\n");
printf("a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化\n");
printf("答案:b\n");
}
};
void test1(){
TestPaper1 p1;
p1.Question1();
p1.Question2();
TestPaper2 p2;
p2.Question1();
p2.Question2();
}
int main(int argc, char** argv)
{
test1();
return 0;
}
控制台输出:
倚天屠龙剑的玄铁可能是:
a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维
答案:b
杨过,程英,陆无双铲除了情花,造成:
a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化
答案:a
倚天屠龙剑的玄铁可能是:
a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维
答案:d
杨过,程英,陆无双铲除了情花,造成:
a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化
答案:b
这种没有任何泛化的代码,重复的部分特别多,后期维护起来也很费力,如果需要增删一个问题活着修改一个问题,都需要做两次同样的操作,效率低下,所以应该将重复部分整合到父类中,子类只需要继承就可以了。修改代码如下:
class TestPaper{
public:
void Question1(){
printf("倚天屠龙剑的玄铁可能是:\n");
printf("a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维\n");
}
void Question2(){
printf("杨过,程英,陆无双铲除了情花,造成:\n");
printf("a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化\n");
}
};
class TestPaperA: public TestPaper {
public:
void testQuestion1(){
Question1();
printf("答案:b\n");
}
void testQuestion2(){
Question2();
printf("答案:a\n");
}
};
class TestPaperB: public TestPaper {
public:
void testQuestion1(){
Question1();
printf("答案:d\n");
}
void testQuestion2(){
Question2();
printf("答案:b\n");
}
};
void test2(){
TestPaperA pA;
pA.testQuestion1();
pA.testQuestion2();
TestPaperB pB;
pB.testQuestion1();
pB.testQuestion2();
}
int main(int argc, char** argv)
{
test2();
return 0;
}
控制台输出的内容相同。
修改以后的代码,将题目部分放到了父类中,子类只需要调用父类的方法然后在子类中给出自己的答案即可,但是这代码还是有重复的地方,就是调用父类的问题这个过程,每个子类还是都做了一遍,所以这部分代码也可以放到父类中去,那子类如果给出自己的答案呢,这里我们可以使用虚方法,子类实现父类给出的作答接口,父类调用这个虚函数即可。
class TestPaperAbstract{
public:
void Question1(){
printf("倚天屠龙剑的玄铁可能是:\n");
printf("a. 球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维\n");
Answer1();
}
void Question2(){
printf("杨过,程英,陆无双铲除了情花,造成:\n");
printf("a. 使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化\n");
Answer2();
}
virtual void Answer1() = 0;
virtual void Answer2() = 0;
};
class TestPaperAA: public TestPaperAbstract {
public:
virtual void Answer1() override{
printf("答案:b\n");
}
virtual void Answer2() override{
printf("答案:a\n");
}
};
class TestPaperBB: public TestPaperAbstract {
public:
virtual void Answer1() override{
printf("答案:d\n");
}
virtual void Answer2() override{
printf("答案:b\n");
}
};
void test3(){
TestPaperAA pAA;
pAA.Question1();
pAA.Question2();
TestPaperBB pBB;
pBB.Question1();
pBB.Question2();
}
int main(int argc, char** argv)
{
test3();
return 0;
}
子类重写Answer1/Answer2虚方法,将自己的答案填上,就实现了和第一份代码相同的功能,将父类的某一方法的实现延迟到子类中,利用了多态性实现了代码复用。
总结
模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。模板方法模式提供了一个很好的代码复用平台。
当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。
总结起来一句话就是,模板模式提取类库中的公共行为到抽象类中。
本文含有隐藏内容,请 开通VIP 后查看