题目描述
- 请将随机生成数字、表达式的部分设计成:一个Random基类,基类中有random()方法。并由该基类派生出RandomNumber类、RandomOperation类,继承并覆盖父类方法。
- 学习简单工厂模式,思考能否将该模式运用到题目的第一点要求中。
作业要求
- 体会继承和多态的思想
- 发表一篇博客,博客内容为:提供本次作业的github链接,题目描述的代码部分的解释、简单工厂模式的学习。
简单工厂模式的学习
- 为什么要使用简单工厂模式:保证代码的可复用,各个子类完全分离,避免了更高代码无意中把原来好的源代码改错,个人只用负责自己对应的子类,不用别的子类。
- 使用简单工程模式的大致流程:告诉工厂你所需要的对象->工厂new出一个对象->工厂返回一个指向该对象的指针。
- 创建简单工厂模式的大致流程:创建定义一个基类(其中包括虚函数)->创建定义多个子类(包括虚函数的新定义)->建立工厂类(建立静态函数,根据不同的输入返回不同对象的指针)。
- 静态的函数中static的含义和好处:“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。 使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。
- 虚函数:简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性,多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。在本次作业中,虚函数的作用是:使用指向不同子类的指针调用虚函数,虚函数的名字和用法都相同,但是作用却不同,这也体现了多态性。
- 简单工厂模式的例子及其代码实现
github链接
主要代码:
//******.h文件中的类实现*******
class Random//基类
{
public:void init();//初始化随机数生成器
virtual int random();
};
class RandomNumber :public Random
{
public:RandomNumber(){}
virtual int random();
};
class RandomOperation :public Random
{
public:RandomOperation(){}
virtual int random();
};
//*******RandomSimpleFactory******
class RandomSimpleFactory//随机类简单工厂
{
public:RandomSimpleFactory(){}
static Random* creatRandom(const string &name);
};
//*******.cpp文件中的函数实现********
//*********Random*************
void Random::init()
{
srand(time(NULL));
}
int Random::random(void)//产生任意的随机数
{
int a = rand();
return a;
}
int RandomNumber::random(void)//获取0~10随机的数字
{
return rand() % 11;
}
int RandomOperation::random(void)//获取随机运算符
{
int sign;
int int_sign;
int_sign = rand() % 4 + 1;
switch (int_sign)
{
case 1:sign = '+'; break;
case 2:sign = '-'; break;
case 3:sign = '*'; break;
case 4:sign = '/'; break;
}
return sign;
}
//*********RandomSimpleFactory*****
Random* RandomSimpleFactory::creatRandom(const string &name)
{
if (name == "Operation")
return new RandomOperation;
else if (name == "Number")
return new RandomNumber;
}
//*********Expression*********
void Expression::randomNumber(void)//获取随机的数字
{
Random* ran = NULL;
string name = "Number";
ran = RandomSimpleFactory::creatRandom(name);
ran->init();
a = ran->random();
b = ran->random();
c = ran->random();
d = ran->random();
}
void Expression::getsign(void)
{
Random* ran=RandomSimpleFactory::creatRandom("Operation");
sign1 = ran->random();
sign2 = ran->random();
sign3 = ran->random();
}
遇到问题
主要问题
- 虚函数的返回类型不同,产生随机数字的子类返回int值,产生随机运算符的子类返回char值,无法成功定义虚函数。
- 尝试的解决办法:
- 使用类模板:在声明和定义类的时候都很自然,但是在简单工厂模式返回一个指针时,就需要定义两个类型指针变量(char和int)来接受返回的指针,在使用时就违背了简单工厂模式的理念,让接口变得复杂。
- 使用函数重载:函数重载只能以参数的类型、个数来区分调用的函数,不能用返回值来调用。
- 使用不同的虚函数名:这样可以实现,但是不如不使用虚函数,虚函数是在函数名和用法相同的情况下,产生不同的作用的函数,要是使用了不同的虚函数名,就无法体现出多态性。
- 最简单的方法:把返回运算符的函数的返回类型设为int,当一个int变量接受char变量值的时候,这个int变量的值就是char所对应的ASC码,将int变量赋值给char 变量时,char变量就会根据这个asc码得到所需的字符。所以只要将虚函数的返回值设为int即可。
其他问题
- 产生的所有数字都一样,原因:把srand()函数和rand()放在了同一个函数里,每次调用这个函数,就srand()一次,程序运行速度非常快,时间相同,所以种子都是相同的,所以产生的随机数都是相同的。
体会
- 简单工厂模式的使用,体现了抽象、封装、继承和多态,使类的封装更完善。
- 虚函数体现了多态和继承,可以函数名相同的问题,简化了函数的使用。
- 这次作业,要求继承并覆盖父类方法,在这个问题上下了一番功夫,尝试了四种方法,在此过程中收获良多。
- 继承和多态的体会,贯穿在上文的“简单工厂模式”实现和“遇到问题”中。类的继承,考验人的抽象能力,要将一个对象,抽象成一个类,再提取出他们的共性,就成了父类,一个抽象的类逐渐具体的过程,就是继承的过程。多态简化了代码,方便了分工。相同的代码无需重新复制粘贴,同名的函数也能有序地共存,编码时只要完成自己的工作,无需过分考虑重名的问题,无形中也简化了编码时的思维量。