代码
这个工厂模式算是简单工厂的升级版,姑且叫它工厂2.0吧,后续还有工厂3.0(抽象工厂更加复杂)。还是采用例子来讲解,例子和前面的简单工厂是一样的,就是加减乘除四个不同算法类,相对比简单工厂,这个设计模式有四个部分,且听我娓娓道来:
- 工厂类基类,是不同算法类工厂的基类,对应下面代码的 i F a c t o r y iFactory iFactory
- 具体的工厂类,对应加减乘除不同算法的具体工厂,对应于下面代码中继承于 i F a c t o r y iFactory iFactory的类
- 算法类的抽象,不同算法的基类,对应下面的 O p e r a t i o n Operation Operation
- 具体的算法类,算法的具体类,对应于下面代码中继承于 O p e r a t i o n Operation Operation的类
看过前面的简单工厂之后,就可以很容易的发现,这里的变化,就是此工厂类不再生产所有的具体算法类了,工厂类也有抽象了,每个不同的具体工厂来生产具体的算法,为何要这样呢,这样代码不就变多了吗。不急不急,后面我会狡辩。咱继续看。
#include <iostream>
#include <string>
using std::string;
class Operation
{
protected:
double numberA;
double numberB;
public:
Operation():numberA(0),numberB(0){};
Operation(double A,double B):numberA(A),numberB(B){};
void setA(double A){numberA = A;};
void setB(double B){numberB = B;};
virtual double getResult() = 0;
};
class OperationAdd : public Operation
{
public:
virtual double getResult(){return numberA + numberB;};
};
class OperationSub : public Operation
{
public:
virtual double getResult(){return numberA - numberB;};
};
class OperationMul : public Operation
{
public:
virtual double getResult(){return numberA * numberB;};
};
class OperationDiv : public Operation
{
public:
virtual double getResult(){return numberA / numberB;};
};
class iFactory
{
public:
virtual Operation * createOperation() = 0;
};
class addFactory : public iFactory
{
public:
virtual Operation * createOperation(){return new OperationAdd();};
};
class subFactory : public iFactory
{
public:
virtual Operation * createOperation(){return new OperationSub();};
};
class mulFactory : public iFactory
{
public:
virtual Operation * createOperation(){return new OperationMul();};
};
class divFactory : public iFactory
{
public:
virtual Operation * createOperation(){return new OperationDiv();};
};
int main()
{
iFactory *operFactory = new addFactory();
Operation *oper = operFactory->createOperation();
oper->setA(1);
oper->setB(2);
std::cout<<oper->getResult()<<"\n";
return 0;
}
详细表述
这里这里算法类和简单工厂是一样的,基类抽象获得具体算法类的值,调用同一个抽象基类的指针,实现不同的算法。我就不多bb了,直接说一下这个工厂类,这里你可以把基类指针(基类引用)和抽象当作同一个概念,可以的,可以的。
- 首先是工厂基类,是一个抽象基类,有一个纯虚函数,因此不能有具体对象,它是用来抽象具体的工厂类的,工厂抽象获得具体工厂类的值,来实现抽象
- 每个不同的算法类,拥有一个不同的工厂,然后算法抽象通过调用工厂抽象的 c r e a t e O p e r a t i o n createOperation createOperation方法(虽然是调用的基类指针,但是c++的运行时判断使得调用了具体工厂类的方法)得到不同的算法类,实现多态
- 然后我们使用的时候直接使用算法基类指针进行调用,采用运行时判断使得不同的类调用不同的虚函数 g e t R e s u l t getResult getResult实现多态
狡辩
ok,下面该我来狡辩前面的坑了,为啥工厂也要实现抽象,每个算法对应特定的工厂呢,假如嗷,我说假如,万一你使用简单工厂模式遇见了需要多个重复算法类的场景,你就的写出下面的代码,对吧(不让用循环嗷)!
Operation *oper1 = nullptr;
oper1 = OperationFactory::creatOperation('/');
Operation *oper2 = nullptr;
oper2 = OperationFactory::creatOperation('/');
Operation *oper3 = nullptr;
oper3 = OperationFactory::creatOperation('/');
现在我遇见一个问题,我不想使用除算法类了想用乘,那你就得改上面的代码,把’/‘改为’*',改三个地方,记住3嗷,下面给你看看使用工厂模式的代码
iFactory *operFactory = new addFactory();
Operation *oper = operFactory->createOperation();
Operation *oper1 = operFactory->createOperation();
Operation *oper2 = operFactory->createOperation();
Operation *oper3 = operFactory->createOperation();
这里我改动的话,只需要把具体的工厂类改了就完事了,就改一处就行了,感受到工厂模式的好处了吧。
例子已经说明好处了,我们再说点专业的话语嗷。那就是设计模式中有大约七个原则吧
- 单一职责原则 (Single Responsibility Principle)
- 开放-关闭原则 (Open-Closed Principle)
- 里氏替换原则 (Liskov Substitution Principle)
- 依赖倒转原则 (Dependence Inversion Principle)
- 接口隔离原则 (Interface Segregation Principle)
- 迪米特法则(Law Of Demeter)
- 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)
我们看看工厂模式比简单工厂模式多满足了啥原则
-
首先单一职责,这个很明显吧,工厂每个具体工厂类只负责一个算法类的生成,而简单工厂负责所有的算法类生成
-
开放-关闭原则,这个有点抽象是吧,没听过这个原则,不好理解吧,hhh,没事,我给你们解释,通俗易懂就是对允许增加代码,但是不允许更改已有代码。我们看看工厂模式怎么符合的,我们上面有四个算法类,加减乘除,现在我要加一个算法类,取模算法类,那么简单工厂要怎么加呢,看下面代码
class OperationFactory { public: static Operation * creatOperation(int operation) { Operation *result = nullptr; switch(operation) { /*... 和前面的简单工厂一样*/ case '%'://here here result = new OperationDiv(); break; } return result; } };
O p e r a t i o n F a c t o r y OperationFactory OperationFactory需要改变,增加一个case,ok开放-关于原则它已破坏,那工厂模式怎么添加代码呢,看下面代码
class OperationMod : public Operation { public: virtual double getResult(){return numberA % numberB;}; };
这里直接新添加一个子类就ok了,不要修改代码,就完成功能了,完美符合开放-关闭原则。
先说者两个吧,应该还有其他的原则,但是我不行了,我找不出来了,有知道的小朋友评论区@我一下嗷。