单例模式就是:一个类只能有一个实例,并提供对该实例的全局访问点。通俗地说,就是一个类只能创建一个对象,并且在程序的任何地方都能够访问到该对象。
在c语言中通俗的话可以这么理解,在一个.c文件中创建一个静态数组或者结构体封装起来,用return或用指针传递的方式返回到需要访问的.c文件中。

下面我以flash模块为例,代码实现单例模式。
适合应用场景:
如果程序中的某个类对于所有客户端只有一个可用的实例,
可以使用单例模式
如果你需要更加严格地控制全局变量,可以使用单例模式
原因是可以代替全局变量,在极端情况下会存在多个线程对一个数据操作存在数据不一致的情况,也不需要重复的创建和销毁变量,可以提高性能以及可以提高可读性。
以下为我在driver_flash.h中创建单例的结构体,和我需要操作的结构体
- #define SWITCHBOT_CONFIG_DATE_MAX_LENGTH 64
-
- typedef struct config_parameter_t
- {
- uint8_t flash_init[4];
- uint8_t electric_alarm_threshold;
- uint8_t electric_alarm_enable;
- uint8_t burglar_alarm_threshold;
- uint8_t burglar_alarm_enable;
- uint8_t led_enable;
- uint8_t work_mode;
- uint8_t ota_update;
- uint32_t ota_end;
-
- uint32_t reserve;
- uint32_t reserve1;
- uint32_t reserve2;//aligmnt
-
- uint32_t reserve3;
- uint32_t reserve4;
- uint32_t reserve5;
- }config_parameter_t;
-
- typedef struct _switchbot_config_t
- {
- uint8_t config[SWITCHBOT_CONFIG_DATE_MAX_LENGTH];
- }switchbot_config_t;
在我的driver_flash.c中实现他的创建他的类,并且把改类封装成接口返回。
- static switchbot_config_t* g_pt_config = NULL;
-
- void *driver_config_get_handle(void)
- {
- return (void*)g_pt_config->config;
- }
在系统初始化时候把flash中数据地址读出放入该实例中。
那么,当我在其他任何.c文件需要使用该flash变量存储或者赋值时,只需导入该drivers_flash.h文件即可调用,且可强转成需用户操作的结构体。
- static void uart_enable_alarm_switch_sensitivity_command(uint8_t* buffer, uint32_t size)/
- {
- config_parameter_t* pt_config = (config_parameter_t*)driver_config_get_handle();
-
- pt_config->burglar_alarm_enable = buffer[0];
-
- /* code */
- }
工厂方法是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
假设你正在开发一款物流管理应用。最初版本只能处理卡车运输,因此大部分代码都在位于名为卡车 的类中。一段时间后,这款应用变得极受欢迎。你每天都能收到十几次来自海运公司的请求,希望应用能够支持海上物流功能如果代码其余部分与现有类已经存在耦合关系,那么向程序中添加新类其实并没有那么容易。这可是个好消息。但是代码问题该如何处理呢?目前,大部分代码都与 卡车 类相关。在程序中添加 轮船 类需要修改全部代码。更糟糕的是,如果你以后需要在程序中支持另外一种运输方式,很可能需要再次对这些代码进行大幅修改。最后,你将不得不编写繁复的代码,根据不同的运输对象类,在应用中进行不同的处理。
- /* 简单工厂类 */
- typedef struct {
- interface_handle_t * (*init)(void);
- int32_t (*write)(interface_handle_t *handle, interface_buffer_handle_t *buf_handle);
- interface_buffer_handle_t * (*read)(interface_handle_t *handle);
- esp_err_t (*reset)(interface_handle_t *handle);
- void (*deinit)(interface_handle_t *handle);
- } if_ops_t;
-
- typedef struct {
- if_ops_t *if_ops;
- } interface_context_t;
-
- interface_context_t *if_context = NULL;
-
- if_ops_t if_xr_ops = {
- .init = xr_spi_init,
- .write = xr_spi_write,
- .read = xr_spi_read,
- .reset = xr_spi_reset,
- .deinit = xr_spi_deinit,
- };
-
- if_ops_esp_t if_esp_ops = {
- .init = esp_spi_init,
- .write = esp_spi_write,
- .read = esp_spi_read,
- .reset = esp_spi_reset,
- .deinit = esp_spi_deinit,
- };
-
- interface_handle_t * xr_spi_init(void)
- {
- /* code */
- }
-
- int32_t * xr_spi_write(void)
- {
- /* code */
- }
-
- interface_buffer_handle_t * xr_spi_read(void)
- {
- /* code */
- }
-
- esp_err_t * xr_spi_reset(void)
- {
- /* code */
- }
-
- void * xr_spi_deinit(void)
- {
- /* code */
- }
-
- interface_handle_t * esp_spi_init(void)
- {
- /* code */
- }
-
- int32_t * esp_spi_write(void)
- {
- /* code */
- }
-
- interface_buffer_handle_t * esp_spi_read(void)
- {
- /* code */
- }
-
- esp_err_t * esp_spi_reset(void)
- {
- /* code */
- }
-
- void * esp_spi_deinit(void)
- {
- /* code */
- }
-
- interface_context_t *interface_insert_driver(uint8_t val)
- {
- printf("Using SPI interface");
-
- /* 根据设备型号不同来进行不同产线的生产 */
- if(val == esp_spi)
- {
- memset(&if_esp_context,0,sizeof(if_esp_context));
- if_context.if_ops->init = esp_spi_init;
- if_context.if_ops->write = esp_spi_write;
- if_context.if_ops->read = esp_spi_read;
- if_context.if_ops->reset = esp_spi_reset;
- if_context.if_ops->deinit = esp_spi_deinit;
- }
- else if(val == xr_spi)
- {
- memset(&if_xr_context,0,sizeof(if_xr_context));
- if_context.if_ops->init = xr_spi_init;
- if_context.if_ops->write = xr_spi_write;
- if_context.if_ops->read = xr_spi_read;
- if_context.if_ops->reset = xr_spi_reset;
- if_context.if_ops->deinit = xr_spi_deinit;
- }
-
- return &if_context;
- }
-
- int main()
- {
- uint8_t spi_mode;
- interface_insert_driver(spi_mode);
- }
-
-
-
-
1.需要创建的对象比较少。
在上面的例子中,我们只是创建了两个鼠标实现类,如果需要几十个上百个具体的实现类的情况,那么在工厂类的switch或者if else语句中就要写很多行代码,很笨重。
2.客户端不关心对象的创建过程
该特点同样适用与其他工厂模式。上面的例子中,就不需要了解DellMouse或者HpMouse实例的创建过程,直接在需要的地方传入不同参数调用就好了
关于单例模式和简单工厂模式已经写完了,写的可能有一些bug,有错误请各位及时提出,谢谢大家