【创建型】简单工厂模式&工厂方法
简单工厂模式
简单工厂模式,其实不算23种设计模式之一,它引入了创建者的概念,将实例化的代码从客户端代码中抽离,交给服务端维护
Java代码实现
需求:服务端开发一个计算器功能,完成加减乘除运算操作
根据简单工厂模式,可以画出它的UML类图如下:
1、需要一个产品抽象类(Operation父类)、工厂类、具体的实现类(AddOperation...)
2、Operation类中有操作数x和y,以及获取结果的函数getResult()
3、工厂类OperationFactory类创建具体的Operation,其中OperationFactory类依赖Operation类
服务端代码
public class OperationFactory {
public static Operation createOperation(String operate) {
Operation operation = null;
switch (operate) {
case "+":
operation = new AddOperation();
break;
case "-":
operation = new SubOperation();
break;
case "*":
operation = new MulOperation();
break;
case "/":
operation = new DivOperation();
break;
}
return operation;
}
}
public abstract class Operation {
double x;
double y;
double result;
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
public double getResult() throws Exception {
return result;
}
}
public class AddOperation extends Operation {
@Override
public double getResult() {
return x + y;
}
}
public class SubOperation extends Operation {
@Override
public double getResult() throws Exception {
return x - y;
}
}
public class MulOperation extends SubOperation {
@Override
public double getResult() throws Exception {
return x / y;
}
}
public class DivOperation extends MulOperation {
@Override
public double getResult() throws Exception {
if (0 == y) {
throw new Exception("除数不能为0");
}
return x / y;
}
}
客户端代码
public class Main {
public static void main(String[] args) throws Exception {
Operation operation = OperationFactory.createOperation("+");
operation.setX(1);
operation.setY(2);
System.out.println(operation.getResult()); // print 3.0
}
}
C代码实现
需求:某一项目需要用到 eeprom、flash 这两个设备保存不同数据,有初始化、读、写三个功能,后续有可能扩展设备
服务端代码:
需要定义设备类型flash.c
flash.h
eeprom.c
eeprom.h
// flash.c
#include <stdint.h>
#include <stdio.h>
#include "factory_function.h"
void flash_init(void) {
printf("初始化 FLASH\n");
}
void flash_open(void) {
printf("启用 FLASH\n");
}
void flash_write(uint32_t addr, uint8_t *data, uint16_t len) {
printf("向FLASH 地址:%x 写入%d 字节数据:%s\n", addr, len, (char *) data);
// eeprom.c
#include <stdint.h>
#include <stdio.h>
void eeprom_init(void) {
printf("初始化 EEPROM\n");
}
void eeprom_open(void) {
printf("启用 EEPROM\n");
}
void eeprom_write(uint32_t addr, uint8_t *data, uint16_t len) {
printf("向EEPROM 地址:%x 写入%d 字节数据:%s\n", addr, len, (char *) data);
}
需要定义工厂方法:
// factory_function.c
#include <string.h>
#include "factory_function.h"
#include "flash.h"
#include "eeprom.h"
typedef struct {
char *name;
void (*init)(void);
void (*open)(void);
void (*write)(uint32_t, uint8_t *, uint16_t);
} Storage;
Storage storage_list[] = {
{"eeprom", eeprom_init, eeprom_open, eeprom_write},
{"flash", flash_init, flash_open, flash_write},
};
Storage *factory_pro(char *name) {
for (int i = 0; i < sizeof(storage_list) / sizeof(storage_list[0]); ++i) {
if (0 == strcmp(name, storage_list[i].name)) {
storage_list->init();
storage_list->open();
return &storage_list[i];
}
}
return NULL;
}
客户端代码
void test_01_factory_method() {
char *str[] = {"我是EEPROM", "我是FLASH"};
Storage *byte_data = factory_pro("eeprom");
Storage *sector_data = factory_pro("flash");
byte_data->write(0x0100, str[0], strlen(str[0]));
sector_data->write(0x02000100, str[1], strlen(str[1]));
}
模式应用
1、JDK类库中广泛使用了简单工厂模式,如工具类java.text.DateFormat,它用于格式化一个本地日期或者时间
public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale locale);
2、获取不同加密算法的密钥生成器
KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
总结
简单工厂模式下,后续拓展功能,需要侵入式的修改工厂中的代码,违反了开闭原则,但是客户端代码不用修改。
C语言的简单工厂模式和面向对象的Java略有不同
1、Java用的继承和多态的思想按需动态的创建所需要的类型
2、C语言用循环遍历的方式来寻找具体的类型并执行方法
工厂方法
需求:服务端开发一个计算器功能,完成加减乘除运算操作。
相比简单工厂模式,工厂方法的UML类图如下:
针对不同的操作,有不同的工厂,这种修改带来了优点是减少侵入式修改,但是会增加服务端的开发量同时客户端需要适配