一、前言
上周学习了抽象工厂模式,该模式包含了简单工厂模式和工厂方法的某些特性,三者之间的区别详见:上周博客,本周深入了解一下简单工厂模式,并对其进行优化,实现一个可动态注册的简单工厂,本次练习参考了AWTK源码中 widget_factory 的实现,感兴趣的可以查阅源码,GitHub仓库:https://github.com/zlgopen/awtk。
AWTK是 ZLG 开发的开源 GUI 引擎,官网地址:https://www.zlg.cn/index/pub/awtk.html。
二、简单工厂模式
简单工厂模式(Factory Pattern)是属于创建型模式,在该模式中,用户通过使用一个共同的接口来创建的具体对象。
简单理解:工厂是对具体产品(对象)的抽象,工厂提供统一接口创建不同的产品。本质上就是定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
目的:给用户提供一个创建一系列相关对象的接口,但用户是不需要指定它们的具体类,其主要是解决接口选择的问题。
优点:
- 一个调用者想创建一个对象,只要知道其名称就可以了。
- 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
- 屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
通常情况下简单工厂模式中的工厂类是静态实现的,即具体对象的构造函数写在工厂类的代码中,那么在新增产品时,就需要修改工厂类的代码,比较麻烦,因此需要进行优化,让工厂类提供动态注册的功能,方便用户可以在从外部直接向工厂类添加新产品,接下来我们来看一个示例。
三、示例类图及C语言代码
3.1 示例介绍
假如要实现一个画笔功能,可以画不同的形状(shape),此处有具体产品方形(square)和圆形(circle),它们具有的绘制(draw)行为,并且需要实现一个具有动态注册功能的形状工厂(shape_factory),让用户可从外部新增具体形状。
3.2 示例类图
首先需要创建 shape_t 接口以及实现该接口的具体类。下一步是创建工厂类 shape_factory_t ,实现它的动态注册功能,提供给用户使用。
3.3 C语言实现
1、创建 shape_t 接口
/* shape.h */
#ifndef SHAPE_H
#define SHAPE_H
#include "awtk.h"
BEGIN_C_DECLS
typedef struct _shape_t shape_t;
typedef struct _shape_vtable_t shape_vtable_t;
typedef shape_t* (*shape_create_t)();
typedef ret_t (*shape_destroy_t)(shape_t* shape);
typedef ret_t (*shape_draw_t)(shape_t* shape);
struct _shape_vtable_t {
uint32_t size;
const char* type;
shape_create_t create;
shape_destroy_t destroy;
shape_draw_t draw;
};
/**
* @class shape_t
* 形状接口,具体形状的基类。
*/
struct _shape_t {
/**
* @property {shape_vtable_t*} vt
* 虚函数表。
*/
const shape_vtable_t* vt;
};
/**
* @method shape_create
* 创建shape对象(仅在子类构造函数中使用)。
* @param {shape_vtable_t*} vt 虚表。
* @return {shape_t*} shape对象本身。
*/
shape_t* shape_create(const shape_vtable_t* vt);
/**
* @method shape_destroy
* 销毁shape对象。
* @param {shape_t*} shape 形状对象。
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t shape_destroy(shape_t* shape);
/**
* @method shape_draw
* 绘制(此处模拟对象行为)。
* @param {shape_t*} shape 形状对象。
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t shape_draw(shape_t* shape);
/* 子类类型常量 */
#define SHAPE_TYPE_SQUARE "square" /* 方形 */
#define SHAPE_TYPE_CIRCLE "circle" /* 圆形 */
#endif /* SHAPE_H */
/* shape.c */
#include "shape.h"
shape_t* shape_create(const shape_vtable_t* vt) {
return_value_if_fail(vt != NULL, NULL);
/* 初始化子类虚函数表 */
shape_t* shape = TKMEM_ALLOC(vt->size)