首页 > 设计模式 之美 -- 简单工厂模式

设计模式 之美 -- 简单工厂模式

文章目录

          • 1. 解决问题
          • 2. 应用场景
          • 3. 实现
            • C++实现:
            • C语言实现
          • 4. 缺点

1. 解决问题

举例如下:

我们实现一个卖衣服的功能,衣服的种类有很多:帽子,裤子,T恤。。。 每卖一种衣服,我们都要进行一次实例化,通过new/malloc申请空间,会有如下两种问题:

  1. new /malloc之后往往需要跟随一堆异常处理代码,当衣服种类越来越多,我们的代码会显得异常臃肿。
  2. 当新的服务员来到商店,他想要卖衣服,但是不知道买衣服的流程(从哪个仓库取出来?进行什么样的加工。。。。)

此时,简单工厂就能解决这样的问题

  1. 简单工厂模式将 new/malloc以及一些衣服的加工操作 进行封装,并不会暴露给外界,将对象的创建和使用完全分离。
  2. 新来的同事不需要知道 卖衣服的具体流程,直接调用生产函数拿到衣服的对象,直接卖就可以。

总之,建立对象的类就像加工一个产品,使用产品的人不需要知道我的产品怎么加工的,只需要使用工厂生成产品,直接用即可。从软件开发角度来说,工厂模式降低了模块之间的耦合度。

2. 应用场景
  1. 针对需要大量实例化对象的类 的设计
  2. 逻辑处理是简单单一的场景
3. 实现

维护一个工厂类,专门负责创建不同的产品,创建产品的内容由工厂自己决定。

C++实现:

实现功能:简单工厂模式 创建不同种类的衣服,直接售卖,而不需要关心衣服的创建 销毁逻辑。

#include using namespace std;/*工厂的可以制造的衣服种类*/
enum ClothType{ hat,paths};class Cloth{ public:virtual void createCloth(void) = 0;virtual ~Cloth(){ } //定义为虚函数,对象空间回收时则会调用子类的析构含糊是
};/*帽子类*/
class Hat: public Cloth{ public:Hat(){ cout << "Hat::hat()" << endl;}virtual void createCloth(void) { cout << "Hat::createHat()" << endl;}~Hat(){ cout << "Hat::delete()" << endl;}
};/*裤子类*/
class Paths: public Cloth{ public:Paths(){ cout << "Paths::paths()" << endl;}virtual void createCloth(void) { cout << "Paths::createPaths()" << endl;}~Paths(){ cout << "Paths::delete()" << endl;}
};/*工厂类,负责不同的衣服的生产*/
class clothFactory {  public:Cloth * createSpecificCloth(ClothType type) { switch(type){ case hat:return (new Hat());case paths:return (new Paths());default:return NULL;}}
};int main()
{ clothFactory cloFac;Cloth *clothA = cloFac.createSpecificCloth(hat);//制造帽子Cloth *clothB = cloFac.createSpecificCloth(paths);//制造裤子clothA -> createCloth();clothB -> createCloth();delete clothA;delete clothB;return 0;
}

编译运行输出如下:

Hat::hat()
Hat::createHat()
Paths::paths()
Paths::createPaths()
Hat::delete()
Paths::delete()
C语言实现

实现功能:和C++实现的功能一样,通过简单工厂封装衣服的创建逻辑,通过工厂创建出指定的衣服对象,直接使用。

实现逻辑:函数指针

retval.h 规范返回值,以及free逻辑

#include 
#include #define return_if_fail(p)if(!(p)){printf("%s:%d Warning:"#p"Failed
",__func__,__LINE__);
eturn;}#define return_val_if_fail(p, ret)if(!(p)){printf("%s:%d Warning:"#p"Failed
",__func__,__LINE__);
eturn (ret);}#define SAFE_FREE(p) if(p != NULL){free(p); p = NULL;}

cloth.h 衣服厂商

#ifndef __CLOTH_H__
#define __CLOTH_H__#include 
#include 
#include "retval.h"struct _Cloth;
typedef struct _Cloth Cloth;typedef Cloth* (*createClothFunc)();
typedef void (*deleteClothFunc)(Cloth* thiz);struct _Cloth 
{ createClothFunc createCloth;deleteClothFunc deleteCloth;
};static inline Cloth* oper_createCloth(Cloth *thiz) { return_val_if_fail(thiz != NULL,NULL);return thiz -> createCloth();
} static inline void oper_deleteCloth(Cloth *thiz) { if (NULL != thiz && NULL != thiz -> deleteCloth ) { thiz -> deleteCloth(thiz);}return;
}#endif

hat.h

#include 
#include "cloth.h"typedef struct _Hat Hat;typedef Cloth* (*createHatClothFunc)();
typedef void (*deleteHatClothFunc)(Hat* thiz);struct _Hat { createHatClothFunc createHatCloth;//创建帽子deleteHatClothFunc deleteHatCloth;//删除帽子
};Hat * oper_hat_create(void);//创建帽子对象

hat.c

#include 
#include "retval.h"
#include "hat.h"static Cloth* oper_createHatCloth()
{ Cloth *cloth = malloc(sizeof(cloth));if(cloth != NULL) {  printf("create hat cloth
");}return cloth;
}static void oper_deleteHatCloth(Hat* thiz) { printf("delete hat cloth
"); if(thiz != NULL) { SAFE_FREE(thiz);}return;
} Hat * oper_hat_create(void) { Hat *thiz = (Hat *)malloc(sizeof(Hat));if(thiz != NULL) { thiz -> createHatCloth = oper_createHatCloth;thiz -> deleteHatCloth = oper_deleteHatCloth;}return thiz;
}

path.h

#include 
#include "cloth.h"typedef struct _Path Path;typedef Cloth* (*createPathClothFunc)();
typedef void (*deletePathClothFunc)(Path* thiz);struct _Path { createPathClothFunc createPathCloth;//创建裤子deletePathClothFunc deletePathCloth;//删除裤子
};/*创建裤子对象*/
Path * oper_path_create(void); 

path.c

/*裤子类,封装了对象的创建和删除*/
#include 
#include "retval.h"
#include "path.h"static Cloth* oper_createHatCloth() //创建
{ Cloth *cloth = malloc(sizeof(cloth));if(cloth != NULL) {  printf("create paths cloth
");}return cloth;
}static void oper_deletePathCloth(Hat* thiz) { //删除printf("delete paths cloth
"); if(thiz != NULL) { SAFE_FREE(thiz);}return;
} Hat * oper_path_create(void) { Path *thiz = (Path *)malloc(sizeof(Path));if(thiz != NULL) { thiz -> createPathCloth = oper_createHatCloth;thiz -> deletePathCloth = oper_deletePathCloth;}return thiz;
}

factory.c

#include 
#include 
#include #include "hat.h"
#include "paths.h"
#include "cloth.h"
#include "retval.h"
#include "factory.h"/*通过传入的字符类型 clothName 来表示要创建对应的衣服对象*/
Cloth* factory_create_op(char clothName) { Cloth *cloth = (Cloth*) malloc(sizeof(Cloth));if(NULL != cloth) { switch (clothName) { case 'h':cloth = (Cloth*)oper_hat_create();break;case 'p':cloth = (Cloth*)oper_path_create();break;default:;}}	return cloth;
}/*释放工厂对象*/
void facory_delete_op(Factory *thiz) { assert(thiz != NULL);SAFE_FREE(thiz);
}Factory *FactoryCreate(void) { Factory *thiz = malloc(sizeof(Factory));if(thiz != NULL){ thiz -> create_op = factory_create_op;thiz -> delete_op = facory_delete_op;}return thiz;
}

factory.h

#ifndef __FACTORY_H__
#define __FACTORY_H__#include 
#include "cloth.h"typedef struct  _Factory Factory;typedef Cloth* (*factoryCreateFunc)();
typedef void (*factoryDeleteFunc)(Factory *thiz);struct _Factory{ factoryCreateFunc create_op;factoryDeleteFunc delete_op;
};Factory *FactoryCreate(void);
Cloth* factory_create_op(char clothName);
void facory_delete_op(Factory *thiz);#endif

main.c

#include 
#include #include "factory.h"
#include "cloth.h"int main(int argc, char *argv[]) { Factory *factory = FactoryCreate();Cloth *clothA = factory_create_op('h');oper_createCloth(clothA);oper_deleteCloth(clothA);Cloth *clothB = factory_create_op('p');oper_createCloth(clothB);oper_deleteCloth(clothB);	factory->delete_op(factory);return 0;
}

编译输出如下:

create hat cloth
delete hat cloth
create paths cloth
delete paths cloth
4. 缺点

通过以上的实现,我们很明显的发现当增加商品的时候需要修改工厂,同时无法增加除了衣服之外的其他种类商品。

  1. 违反了开闭原则:简单工厂模式在扩展产品的时候需要去修改工厂。开闭原则讲究的是对扩展开发,对修改关闭。
  2. 不支持扩展新种类的商品。

更多相关:

  • 关于点云的分割算是我想做的机械臂抓取中十分重要的俄一部分,所以首先学习如果使用点云库处理我用kinect获取的点云的数据,本例程也是我自己慢慢修改程序并结合官方API 的解说实现的,其中有很多细节如果直接更改源程序,可能会因为数据类型,或者头文件等各种原因编译不过,会导致我们比较难得找出其中的错误,首先我们看一下我自己设定的一个场景,...

  • /* 使用正态分布变换进行配准的实验 。其中room_scan1.pcd room_scan2.pcd这些点云包含同一房间360不同视角的扫描数据 */ #include #include #include #include

  • #include #include #include #include ...

  • #include #include #include #include #include #include...

  • #include #include #include #include int main (int argc,...