简单工厂模式
书里面是讲了一些故事,来描述着些问题,这里就不描述了,直接用我的表达方式。
首先要清楚几个概念:面向对象的三大特性是: 封装,继承,多态。
{
封装:为了实现复用和灵活性,实现业务逻辑和界面逻辑分离(这个比较重要)
{
例子:活字印刷
{
1.要改,只需要改要改之子 ---可维护。
2.这些字在以后的印刷中还能用 ---可复用。
3.要加字,只要另刻加入 ---可扩展。
4.字的排序可竖也可横 ---灵活性
}}
继承:一定程度上也是为了提高灵活性,重用性,同时也是为了能符合开发的一些具体要求(后面的例子会让你理解)。
{
继承能让逻辑更加清晰,同时通过类的分层细化和实现也可以做到灵活应用,同时也是为了实现一些设计模式的前提。
}
多态: {以后补充。}
}
面向对象的目的:
其实也就是他的三大特性,为了让程序灵活,可复用,可维护,同时方便一些设计模式和思路的实现。
面向对象和面向过程的区别:(每个人理解都不一样)
{
我的理解是面向过程是:考虑的是实现,给你一个问题,第反应就是怎么实现,能不能实现,具体某个细节的逻辑怎么写,函数里面怎么写等等,最典型的就是之前在ACM的思路,解决问题的过程通常是这样
1.读懂题(四级没过...)
2.考虑思路(怎么解决问题,需要用那个算法,到底是属于那个论里面的,哎!)
3.确定之后就直接(*注意是直接)去实现,然后提交,然后Ac或者Wa...
这就是典型的面向过程思维,遇到问题第一思考方式是算法,目的只有一个,解决问题。而面向对象是指,遇到问题,我的第一反应是数据,哪些数据应该放到那个类里面,怎样更灵活,是否需要把所有数据放大一个DataClass里,是否还需要封装出来一个计算统计数据的类,而这些类是直接放到DataClass里还是直接单独成类,如果是单独成类,那么他们的关系是继承还是关联等,最终的目的是为了在解决问题的前提下适应各种新问题。
}
问题:
面试题目,用随便一种语言实现一个加减乘除的四则运算(不考虑大数问题以及小数问题,默认就是int,我通过5个样例来进化这个代码的实现)
1.基本实现->2.健壮实现->3.封装实现界面逻辑和业务逻辑分离->4.继承,实现工资安全->5.工厂模式实现
1.基本实现:
void Fun1()
{
int A ,B;
char C;
cin>>A;
cin>>B;
cin>>C;
if(C=='+') cout << A + B;
if(C=='-') cout << A - B;
if(C=='*') cout << A * B;
if(C=='/') cout << A / B;
getchar();
return ;
}
优点:貌似是除了写的省事能快点以外没啥优点。缺点:
1.没注意基本编码风格,变量名,函数名;
2.健壮性太差了,除法0就跪了。
3.时间复杂度的问题,三个if浪费时间,这个和for(int i = 1 ;i <= strlen(str) ;i ++)**;这个语句犯的是同一个问题,记得当时做算法题我还因为这个TLE过。
4.可移植性和封装性等完全没有,这么写估计就是 “技术官都没见到,就直接HR:你回去吧 有消息我们通知你”。
2.规范和健壮性实现
void FOperation()
{
int nNumberA ,nNumberB;
string strOpe = "";
try
{
cin >> nNumberA;
cin >> nNumberB;
cin >> strOpe;
if(nNumberB == 0 && strOpe[0] == '/')
{
cout << "不能除0";
return ;
}
switch(strOpe[0])
{
case '+' : cout << nNumberA + nNumberB << endl;break;
case '-' : cout << nNumberA - nNumberB << endl;break;
case '*' : cout << nNumberA * nNumberB << endl;break;
case '/' : cout << nNumberA * nNumberB << endl;break;
default :cout << "无法识别输入的字符" ;break;
}
}
catch(void *pErrorKey)
{
cout <<"error"<<endl;
}
return ;
}
优点: 健壮性比之前好一点了,起码有try catch 同时除0有警告,变量定义也规范一点了。
缺点: 没有考虑可移植性,也没有封装,而且我个人觉得这个函数作为接口看着也难受我习惯这样的 bool FunAA(const int &nA ,const int &nB ,int nResult);
Tip: 想起来一个东西,就是在switch里面的那个四个符号的顺序问题,可以通过数据统计,然后根据概率进行最大化的时间复杂度优化。
3.封装实现界面逻辑和业务逻辑分离
这个就不写了,其实就是把上面的那个写在一个类里,然后留出一个public的接口函数给使用者用,对了注意一点,复用和复制不是一回事。
缺点: 灵活性相对来说还是比较差,不容易扩展,类的层次感也没有这样东西多了逻辑很乱,不符合面向对象的思维。
这个也不写了,3和4的改进最后都会在5里面写,这个的实现是定义一个类作为基类,然后扩展出来一个类继承这个类,然后实现四个运算,调用扩展类来实现。
优点: 考虑到了灵活性和可复用性,但是还是有一点问题,就是在特定的场合可能还是有瑕疵。
缺点: 比如有这么一个场景,公司之前用一个软件给员工计算工资,然后突然想增加一个职位,同时要增加一个新的工资计算方式,
这样实现者就应该去修改那个子类,就是继承了别人给客户端调用的那个类,但是别的人的工资计算方式也在里面,这样就容易出现
有意或者无意的引入新的问题...
5.工厂模式实现
为了弥补上面的所有缺点,并且优雅的实现一段代码,可以使用简单工厂模式,当然简单工厂模式也有自己的缺点,首先工厂模式的思路是这样
,写一个超类,然后在实现几个继承类,然后在写一个工厂,用户使用的时候直接是调用工厂类,工厂根据传进来的参数来确定是实例话那个继承类,
这样当增加新的模块的时候,只要增加一个自己的继承类,然后在工厂里面加一个自己的分支语句就可以了,这样无法看到别人的实现方式。
实现:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class COperationBaseClass
{
public:
virtual bool GetValue(const int &nNumA , const int &nNumB ,int &nAns) = 0;
};
class CJia:public COperationBaseClass
{
public:
bool GetValue(const int &nNumA , const int &nNumB ,int &nAns)
{
nAns = nNumA + nNumB;
return true;
}
};
class CJian:public COperationBaseClass
{
public:
bool GetValue(const int &nNumA , const int &nNumB ,int &nAns)
{
nAns = nNumA - nNumB;
return true;
}
};
class CCheng:public COperationBaseClass
{
public:
bool GetValue(const int &nNumA , const int &nNumB ,int &nAns)
{
nAns = nNumA * nNumB;
return true;
}
};
class CChu:public COperationBaseClass
{
public:
bool GetValue(const int &nNumA , const int &nNumB ,int &nAns)
{
if(!nNumB)
{
return false;
}
nAns = nNumA / nNumB;
return true;
}
};
class FacMod
{
public:
bool GetFun(const string &strWorkKey ,COperationBaseClass * &pFun)
{
pFun = NULL;
switch (strWorkKey[0])
{
case '+': pFun = new CJia() ;break;
case '-': pFun = new CJian() ;break;
case '*': pFun = new CCheng() ;break;
case '/': pFun = new CChu() ;break;
default : return false;
}
return pFun != NULL;
}
};
调用:
int _tmain(int argc, _TCHAR* argv[])
{
FacMod cFun;
COperationBaseClass * pFun = NULL;
int nAns = 0;
if(cFun.GetFun("+" ,pFun))
{
pFun -> GetValue(1 ,2 ,nAns);
cout<<nAns<<endl;
delete(pFun);
}
else {cout <<"error"<<endl;}
system("pause");
return 0;
}
优点: 工厂模式实现,解决了上面4个的所有缺点,使用灵活。
缺点: 每次增加新模块需要增加修改工厂,这个地方的优化处理方式是抽象工厂模式,以后说这个。