设计模式-简单工厂模式

简单工厂模式

    书里面是讲了一些故事,来描述着些问题,这里就不描述了,直接用我的表达方式。

首先要清楚几个概念:
面向对象的三大特性是: 封装,继承,多态。
{
    封装:为了实现复用和灵活性,实现业务逻辑和界面逻辑分离(这个比较重要)
   {
       例子:活字印刷
       {
          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的接口函数给使用者用,对了注意一点,复用和复制不是一回事。


优点: 实现了封装,可以实现界面逻辑和业务逻辑分离,多个项目都可以复用这个类。

缺点: 灵活性相对来说还是比较差,不容易扩展,类的层次感也没有这样东西多了逻辑很乱,不符合面向对象的思维。


4.继承,实现工资安全
这个也不写了,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个的所有缺点,使用灵活。

缺点: 每次增加新模块需要增加修改工厂,这个地方的优化处理方式是抽象工厂模式,以后说这个。


原文地址:https://www.cnblogs.com/csnd/p/12062375.html