今天居家办公第65天,疫情期间,每天抢菜,抢菜。。抢菜完成之后,就学习一会设计模式吧,今天学习的内容是工厂模式。
个人觉得工厂模式主要是为了把创建对象的代码放到专门的工厂类里,其实把new的工作延迟到子类里,(实际上delete的该工作该模式没有关心),当有新的产品需求后, 就新加个产品子类class,然后再新加个子类工厂的class,一定程度上符合开闭原则。
首先根据依赖倒置原则,面向抽象编程,首先是上层模块(产品)不能依赖于底的模块(工厂),他们都应该依赖于抽象,都得基类接口;然后对于产品和工厂,他们各自的基类接口应该是永远不变,产品和工厂的各自子类都得遵守各自基类中的方法,所以尽量把基类接口写全。
1 设定基类接口
工厂基类.h
class IObject;
class IFactor
{
public:
virtual IObject* CreatObject()=0;
}
产品基类.h
class IObject
{
public:
virtual void doAction()=0;
}
需求:两款抢菜器产品,两个工厂生产抢
霹雳火抢菜器.h
#include "IObject.h"
class FireGrap : public IObject
{
public:
void doAction();
}
呲水枪抢菜器.h
#include "IObject.h"
class WaterGrap:public IObject
{
public:
void doAction();
}
火抢菜器生产工厂.h
#include "IFactor"
class IObject;
class FireFactor: public IFactor
{
public:
IObject* CreatObject();
}
水抢菜器生产工厂.h
#include "IFactor"
class IObject;
class WaterFactor: public IFactor
{
public:
IObject* CreatObject();
}
main.cpp
#include "霹雳火抢菜器.h"
#include "呲水枪抢菜器.h"
#include "水抢菜器生产工厂.h"
#include "火抢菜器生产工厂.h"
int main()
{
IFactor* waterFactor = new WaterFactor();
IObject* waterGarp = waterFactor->CreatObject();
waterGarp->doAction();
}
上述h文件的对应cpp实现
IObject* WaterFactor::CreatObject()
{
return new WaterGrap();
}
IObject* FireFactor::CreatObject()
{
return new FireGrap();
}
void FireGrap::doAction()
{
cout<<"grap success by fireGrap!"
}
void WaterGrap::doAction()
{
cout<<"grap success by WaterGrap!"
}
两个抢菜器不够用,现在需求改了,新增了一个金抢菜器,那就需要一个新的抢菜工厂。
class GoldFactor : public IFactor
{
public:
IObject*CreatObject();
}
class GoldGrap :public IObject
{
public:
void doAction();
}
现在三个抢菜器够用了,但是要新增加一个mask制造厂,生产mask,然后运输蔬菜的人员都要佩戴,那就需要一个新的mask machining 工厂。
class MaskFactor : public IFactor
{
public:
IObject*CreatObject();
}
class Mask:public IObject
{
public:
void doAction();
}
工厂模式其实就是找个类,把产品的new的行为延迟到工厂类里,但是又需要在main里new一个工厂出来,所以可以把工厂写成单例模式,避免出现new关键字,把static 不放到私有成员里,放到getInstance函数内部,保证需要产品的时候,再实例化工厂,以mask工厂为例:
MaskFactor.h
class MaskFactor : public IFactor
{
public:
IObject* CreatObject();
static MaskFactor* GetInstance();
pravite:
MaskFactor();
}
MaskFactor.cpp
MaskFactor* MaskFactor::GetInstance()
{
static MaskFactor instance;
return &instance;
}
int main()
{
Object* mask = MaskFactor::GetInstance();
}
可以看出来,当产品增加,工厂也得增加,类会成倍增加,有没有好办法解决这个问题嘛?思来想去,感觉还是抛弃工厂模式,直接上上一篇的桥接模式来new。为了DIP依赖倒置原则,依旧给产品Object定一个基类,方法和上面写的一样,用于固定接口;然后为了能减少工厂类的数量,工厂Factor新创建一个FactorService基类来当一个桥,然后他包含一个FactorServiceImpl,用来实现new不同产品。
FactorService.h
class FactorServiceImpl;
class IObject;
class FactorService
{
public:
IObject* CreatObject();
private:
FactorServiceImpl* impl;
}
FactorService.cpp
#include "FactorService.h"
#include "FactorServiceImpl.h"
#include "IObject.h"
IObject* FactorService::CreatObject()
{
impl->CreatObject();
}
这样的话,我就可以根据产品需求的变更,任意在FactorServiceImpl更改new的种类,还不会动到main里面的东西,只要FactorServiceImpl没改错,main就不用再测试了,对于main来说也算是勉强符合开闭原则。
FactorServiceImpl.cpp
IObject* CreatObject()
{
//return new WaterGrap();
return new FireGrap();
}
总结来说,工厂模式在实际工程里的用处可能有限,其实还是switch case更直接。