zoukankan      html  css  js  c++  java
  • 设计模式-简单工厂模式

    简单工厂模式

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

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

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


  • 相关阅读:
    使用node.js和socket.io实现多人聊天室
    linux上如何自动获取ip及连接互联网
    大数据 时间同步问题 解决hbase集群节点HRegionServer启动后自动关闭
    大数据环境完全分布式搭建hbase-0.96.2-hadoop2
    大数据环境完全分布式搭建 hadoop2.4.1
    大数据环境完全分布式搭建linux(centos)中安装zookeeper
    虚拟机中操作系统的克隆方法及ip修改及硬件地址修改
    在Windows系统下安装Beautiful Soup4的步骤和方法
    在eclipse中配置Python环境
    python3.4爬取网页的乱码问题
  • 原文地址:https://www.cnblogs.com/csnd/p/12062375.html
Copyright © 2011-2022 走看看