前言
我(长胖的阿诏)是新入行的嵌入式程序员,所以用C语言做示例演示,我看到书上都是 C# 语言的代码,所以我只能先领会精神,再通过C语言复刻。在我的资源里好像没有见过用24k纯C语言来描述设计模式的例子的,所以我只能摸石头过河,如果有大牛看见我的 错误 还请劳烦指出,阿诏先行谢过。
这是同步更新的Gitee地址用于存放写过的源码文件:
https://gitee.com/auyvjpz/design-mode-notes.git
简单工厂模式
"我"的理解
简单工厂模式,顾名思义通过一个“工厂”可以生产出不同的用途的“东西”。
通过编写计算器时,我们需要面对多种计算方法的实现(加、减、乘、除等)。这时最直接的想法是通过switch去选择计算的模式,但是这样写会造成每种计算的代码耦合在一个switch的case组合中,只能说可以实现但是复用性不高。
而简单工厂模式抽象出一个“简单工厂的功能层”,通过“工厂”可以创建不同算法但执行过程相同的“功能对象”,从而应对不同计算方法的实现过程。
UML图解
OperationFactory依赖TOperation的子类创建不同TOperation功能对象
代码实现
// 简单工厂.c
//~~~~ 运算类 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef enum TOperationTypeTag TOperationType;
enum TOperationTypeTag
{
kOptAdd,
kOptSub,
kOptMul,
kOptDiv,
}; ///< 每种计算符号枚举值
// 计算函数类型
typedef float (*TDoCalculate)(TOperation* AObj)
typedef struct
{
float number1; // 参与计算参数1
float number2; // 参与计算参数2
// 每个子类要实现的函数
TDoCalculate __DoCalculate;
} TOperation;
// 调用计算函数
float TOperationDoCalculate(TOperation* AObj)
{
return AObj->__DoCalculate(AObj);
}
// 释放计算类
void TOperationFree(TOperation* AObj)
{
if (AObj != NULL)
free(AObj);
}
//~~~~~~~~~~~~~~~~~ 加法运算类 ~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct
{
TOperation parent; // 继承计算父类
} TAddOperation;
static float L_AddDoCalculate(TOperation* AObj)
{
return AObj->number1 + AObj->number2;
}
void* TAddOperationCreate()
{
TAddOperation* obj = (TAddOperation*)malloc(sizeof(TAddOperation));
if (obj != NULL)
obj->__DoCalculate = L_AddDoCalculate;
return (void*)obj;
}
//~~~~~~~~~~~~~~~~~ 减法运算类 ~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct
{
TOperation parent; // 继承计算父类
} TSubOperation;
static float L_SubDoCalculate(TOperation* AObj)
{
return AObj->number1 - AObj->number2;
}
void* TSubOperationCreate()
{
TSubOperation* obj = (TSubOperation*)malloc(sizeof(TSubOperation));
if (obj != NULL)
obj->__DoCalculate = L_SubDoCalculate;
return (void*)obj;
}
//~~~~~~~~~~~~~~~~~ 乘法运算类 ~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct
{
TOperation parent; // 继承计算父类
} TMulOperation;
static float L_MulDoCalculate(TOperation* AObj)
{
return AObj->number1 * AObj->number2;
}
void* TMulOperationCreate()
{
TMulOperation* obj = (TMulOperation*)malloc(sizeof(TMulOperation));
if (obj != NULL)
obj->__DoCalculate = L_MulDoCalculate;
return (void*)obj;
}
//~~~~~~~~~~~~~~~~~ 除法运算类 ~~~~~~~~~~~~~~~~~~~~~~~~~
typedef struct
{
TOperation parent; // 继承计算父类
} TDivOperation;
static float L_DivDoCalculate(TOperation* AObj)
{
return AObj->number1 / AObj->number2;
}
void* TDivOperationCreate()
{
TDivOperation* obj = (TDivOperation*)malloc(sizeof(TDivOperation));
if (obj != NULL)
obj->__DoCalculate = L_DivDoCalculate;
return (void*)obj;
}
//~~~~~~~~~~~~~~~~~ 运算工厂 ~~~~~~~~~~~~~~~~~~~~~~~~~
// 因为工厂只有一个create方法,所以可以直接以一个函数的形式存在
TOperation* OperationFactoryCreateOperation(int type)
{
TOperation* result = NULL;
switch (type)
{
case kOptAdd :
result = TAddOperationCreate();
break;
case kOptSub :
result = TSubOperationCreate();
break;
case kOptMul :
result = TMulOperationCreate();
break;
case kOptDiv :
result = TDivOperationCreate();
break;
default :
printf("暂不支持 %s 计算\n", GetOptTypeName(type));
}
return result;
}
//~~~~~~~~~~~~~~~~~ 使用示例 ~~~~~~~~~~~~~~~~~~~~~~~~~
int Test()
{
// 选择计算方式
TOperationType sign = InputOptType();
// 创建对应计算对象
TOperation* opt_obj = OperationFactoryCreateOperation(sign);
if (opt_obj != NULL)
{
opt_obj->number1 = InputFloat(); // 获取参数1
opt_obj->number2 = InputFloat(); // 获取参数2
float ret = TOperationDoCalculate(opt_obj); // 得到计算结果
printf("结果为:%f\n", ret);
TOperationFree(opt_obj); // 释放对象
}
return 0;
}
总结
Q: 明明可以简单的用switch用5分钟写完,为什么花半小时敲这么多。
-
首先,这样代码的层次感很强,用户(test函数编写者)只需要按照步骤一步步完成功能的实现。
-
其次,如果需要修改某个计算可以很快的锁定需要改动的位置,修改完成后主函数不需要变动。
-
然后,代码拓展性高,比如添加一个幂次的操作,只需要按照相同的方法复制一个子类即可,然后只在“工厂”中添加一条生产线(case 分支)即可,主函数依旧不需要动。
由此可知,简单工厂抽象了对象的行为,通过“工厂”的方式生产出具有不同行为的对象(这可能就是 多态 ),来执行相同的流程,得到不同的结果。