1 简单工厂模式
函数输入的变量,其类型和名称相同,但是具体传入值不同,
由于某些变量值的不同,引起其执行过程不同,
其返回值类型和名称也相同。
——函数头相同,函数体不同,这为函数重写提供了条件(多态)
比如实现计算器的加减乘除时,无论是哪种运算,都需要两个数和一个运算符。
版本一:参数输入与功能定义放在一起
#include <stdio.h>
int main()
{
double a,b;
char operate;
scanf("%lf %c %lf",&a,&operate,&b);
double result=0;
switch(operate)
{
case '+':result=a+b;break;
case '-':result=a-b;break;
case '*':result=a*b;break;
case '/':result=a/b;break;
defalut:
return 0;
}
printf("%lf",result);
return 0;
}
该方法将控制台输入和功能定义耦合在一起,当进行功能扩展——如增加一个取模运算,或者进行跨平台开发,比如不用cmd输入了,要开发一个Android的版本,那此时直接在原有代码上改动也罢,将逻辑供暖复制到其他平台也罢,都可能因为修改或者直接复制原有代码产生新的bug.
版本二:将计算功能与输入控制分离
#include <iostream>
using namespace std;
class Operation
{
public:
Operation(double operandA,double operandB,char operate)
{
this->operandA=operandA;
this->operandB=operandB;
this->operate=operate;
}
private:
double operandA;
double operandB;
char operate;
public:
void setOperandA(double operandA)
{
this->operandA=operandA;
}
void setOperandB(double operandB)
{
this->operandB=operandB;
}
double getOperandA()
{
return this->operandA;
}
double getOperandB()
{
return this->operandB;
}
double getResult()
{
double result=0;
switch(operate)
{
case '+':result=operandA+operandB;break;
case '-':result=operandA-operandB;break;
case '*':result=operandA*operandB;break;
case '/':result=operandA/operandB;break;
defalut:
return 0;
}
return result;
}
};
int main()
{
double oprA,oprB;
double result;
char opt;
cin>>oprA>>oprB>>opt;
Operation op(oprA,oprB,opt);
result=op.getResult();
cout<<result;
return 0;
}
该版本代码将计算功能单独封装为类,两个运算数和一个运算符分别作为该操作类的私有属性,具体的计算功能是通过该类对外提供的getResult()方法进行的。
这样一来,在主程序调用运算功能时,无需知道运算细节;体现了面向对象的封装性。
此外,功能实现与调用相分离,降低了运算和调用的耦合,若跨平台使用,则仅需复制运算功能类即可,使得代码具有一定的可复用性。
但是,如果还需增加其他运算功能,如取模运算,仍需在运算类的switch中进行代码修改,在取模运算逻辑代码增加的同时,开发者能接触到加减乘除的代码,有机会对已有的加减乘除操作进行修改,从而产生bug甚至其他不安全因素。
版本三:分别对加,减,乘,除 进行类的定义,再定义一个工厂类对功能进行选择,调用类对输入进行控制
#include <iostream>
#include <cmath>
using namespace std;
class Operation
{
public:
Operation(double operandA,double operandB,char operate)
{
this->operandA=operandA;
this->operandB=operandB;
this->operate=operate;
}
protected:
double operandA;
double operandB;
char operate;
public:
void setOperandA(double operandA)
{
this->operandA=operandA;
}
void setOperandB(double operandB)
{
this->operandB=operandB;
}
void setOperate(char operate)
{
this->operate=operate;
}
double getOperandA()
{
return this->operandA;
}
double getOperandB()
{
return this->operandB;
}
char getOperate()
{
return this->operate;
}
virtual double getResult()=0;
};
class AddOperation:public Operation
{
public:
AddOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA+operandB;
}
};
class MinusOperation:public Operation
{
public:
MinusOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA-operandB;
}
};
class MultipleOperation:public Operation
{
public:
MultipleOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA*operandB;
}
};
class DivOperation:public Operation
{
public:
DivOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){
}
double getResult()
{
// cout<<operandB<<endl;
if(fabs(this->operandB)>1e-2)
{
return this->operandA/this->operandB;
}
/ return -1;
// else
// {
cout<<this->operandB<<endl;
//
// cerr<<"wrong"<<endl;
// return -1;
// }
}
};
class OperationFactory
{
public :
Operation *operation=NULL;
public:
Operation* createOperation(double operandA,double operandB,char opt)
{
switch(opt)
{
case '+':
{
AddOperation add(operandA,operandB,opt);
operation=&add;
}
break;
case '-':
{
MinusOperation minus(operandA,operandB,opt);
operation=−
}
break;
case '*':
{
MultipleOperation multiple(operandA,operandB,opt);
operation=&multiple;
}
break;
case '/':
{
DivOperation div(operandA,operandB,opt);
operation=÷
}
break;
default:
break;
}
return operation;
}
};
int main()
{
double oprA,oprB;
double result;
char opt;
cin>>oprA>>oprB>>opt;
OperationFactory factory;
Operation *option=factory.createOperation(oprA,oprB,opt);
result=option->getResult();
cout<<result;
return 0;
}
/*
Operation op;
报错信息二cannot declare field "xxx" to be of abstract type"xxx"
报错原因:把c++抽象类(含纯虚函数的类叫抽象类)当做成员对象,因为抽象类不可实例化,解决方法把实例对象改成指针
case '+':AddOperation add(operandA,operandB,operate);operation=&add;break;
https://blog.csdn.net/zzwdkxx/article/details/27561393
在case '+' 中定义的add对象在其他cae中仍然有效
*/
优点:
将各个功能操作——加减乘除——各自被封装为一类,因输入输出类型相同,故都继承自同一父类。在进行功能扩展添加时,无需在原有的功能类中进行修改,而是新定义一个功能类。扩展性较好。
将产品定义,产品生产,产品调用的三部分代码相分离。对产品生产者隐藏了产品定义细节,对产品使用者隐藏了产品生产的细节。
缺点:
此外,在添加功能时,需要对选择要生产何种产品的工厂类添加分支,对于工厂类而言,不满足“开放-封闭”原则。
2 工厂方法模式
简单工厂模式,在新增功能时,需对已有的工厂类代码中的选择产品进行分支的添加,不满足对修改封闭的原则。
仍然是简单的计算器加减乘除。
#include <iostream>
#include <cmath>
using namespace std;
class Operation
{
public:
Operation(double operandA,double operandB,char operate)
{
this->operandA=operandA;
this->operandB=operandB;
this->operate=operate;
}
protected:
double operandA;
double operandB;
char operate;
public:
void setOperandA(double operandA)
{
this->operandA=operandA;
}
void setOperandB(double operandB)
{
this->operandB=operandB;
}
void setOperate(char operate)
{
this->operate=operate;
}
double getOperandA()
{
return this->operandA;
}
double getOperandB()
{
return this->operandB;
}
char getOperate()
{
return this->operate;
}
virtual double getResult()=0;
};
class AddOperation:public Operation
{
public:
AddOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA+operandB;
}
};
class MinusOperation:public Operation
{
public:
MinusOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA-operandB;
}
};
class MultipleOperation:public Operation
{
public:
MultipleOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){}
double getResult()
{
return operandA*operandB;
}
};
class DivOperation:public Operation
{
public:
DivOperation(double operandA,double operandB,char operate):Operation( operandA, operandB, operate){
}
double getResult()
{
// cout<<operandB<<endl;
if(fabs(this->operandB)>1e-2)
{
return this->operandA/this->operandB;
}
return -1;
// else
// {
cout<<this->operandB<<endl;
//
// cerr<<"wrong"<<endl;
// return -1;
// }
}
};
class InterfaceOperationFactory
{
public:
Operation *op=NULL;
virtual Operation *createOperation(double operandA,double operandB,char opt )=0;
};
class AddOperationFactory:public InterfaceOperationFactory
{
public:
Operation *createOperation(double operandA,double operandB,char opt )
{
AddOperation add(operandA,operandB,opt );
op=&add;
return op;
}
};
class MinusOperationFactory :public InterfaceOperationFactory
{
public:
Operation *createOperation(double operandA,double operandB,char opt )
{
MinusOperation minus(operandA,operandB,opt );
op=−
return op;
}
};
class MultipleOperationFactory:public InterfaceOperationFactory
{
public:
Operation *createOperation(double operandA,double operandB,char opt )
{
MultipleOperation multiple(operandA,operandB,opt );
op=&multiple;
return op;
}
};
class DivOperationFactory:public InterfaceOperationFactory
{
public:
Operation *createOperation(double operandA,double operandB,char opt )
{
DivOperation div(operandA,operandB,opt );
op=÷
return op;
}
};
int main()
{
double oprA,oprB;
double result;
char opt;
cin>>oprA>>oprB>>opt;
//定义抽象工厂和子类工厂,让抽象工厂引用指向子类工厂对象
InterfaceOperationFactory *factory;
DivOperationFactory addFactory;
factory=&addFactory;
//使用工厂的多态生产 产品
Operation *operation=factory->createOperation(oprA,oprB,opt);
//使用产品的多态输出产品结果
cout<<operation->getResult();
return 0;
}
-
优点:将对工厂的修改封闭起来,在工厂类部分满足了开放-封闭原则。若要进行计算器的功能添加,只要分别继承运算类,工厂类。调用时需要修改实际操作对应的子工厂类,将修改从产品生产模块移到了产品调用模块。
缺点:每新增一个产品,需要创建一个对应的工厂类,增加代码量。
参考文献
《大话设计模式》 程杰