【创建型】简单工厂模式&工厂方法

简单工厂模式

简单工厂模式,其实不算23种设计模式之一,它引入了创建者的概念,将实例化的代码从客户端代码中抽离,交给服务端维护

Java代码实现

需求:服务端开发一个计算器功能,完成加减乘除运算操作

根据简单工厂模式,可以画出它的UML类图如下:

1、需要一个产品抽象类(Operation父类)、工厂类、具体的实现类(AddOperation...)

2、Operation类中有操作数x和y,以及获取结果的函数getResult()

3、工厂类OperationFactory类创建具体的Operation,其中OperationFactory类依赖Operation类

image

服务端代码

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类图如下:

针对不同的操作,有不同的工厂,这种修改带来了优点是减少侵入式修改,但是会增加服务端的开发量同时客户端需要适配
image

posted @ 2020-06-25 16:12  __Helios  阅读(334)  评论(0编辑  收藏  举报