当前位置: 首页 > news >正文

设计模式(策略,观察者,单例,工厂方法)

文章目录

    • 1. 设计模式核心概念与C语言实现基础
    • 2. 常用设计模式详解
      • 模式一:策略模式(Strategy Pattern)
      • 模式二:观察者模式(Observer Pattern)
      • 模式三:单例模式(Singleton Pattern)
      • 模式四:工厂方法模式(Factory Method Pattern)

1. 设计模式核心概念与C语言实现基础

设计模式是一套被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中一些不断重复发生的问题,以及该问题的解决方案的核心。

在C语言中实现设计模式,主要依赖于以下技术来模拟面向对象特性:

  • 结构体(Structs): 用于封装数据,模拟类的属性。
  • 函数指针(Function Pointers): 用于封装行为,模拟类的方法。这是实现多态(Polymorphism)继承(Inheritance) 的关键。
  • 头文件(.h)和源文件(.c): 用于实现封装(Encapsulation) 和信息隐藏。头文件暴露结构体和公共函数接口,源文件隐藏私有数据和实现细节。
  • void指针(void*): 用于实现泛型编程,处理未知类型的数据。

2. 常用设计模式详解

以下选择四个在系统级嵌入式中间件等C语言主导领域非常实用的模式。

模式一:策略模式(Strategy Pattern)

1、意图
定义一系列算法,将每个算法封装起来,并使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

2、UML图示

uses
Context
-Strategy *strategy
+setStrategy(Strategy*)
+executeStrategy()
«interface»
Strategy
+execute()
ConcreteStrategyA
+execute()
ConcreteStrategyB
+execute()
  • Context:持有一个策略对象的引用,用接口与策略对象交互。
  • Strategy:策略接口,声明了所有具体策略的通用方法(execute)。
  • ConcreteStrategy:实现了策略接口的具体算法。

3、C代码实现

//--- strategy.h ---
// 声明策略接口(用结构体模拟)
typedef struct Strategy Strategy;
struct Strategy {void (*execute)(void); // 函数指针,代表算法接口
};// 上下文类,用于连接策略
typedef struct Context Context;
struct Context {Strategy *strategy;void (*setStrategy)(Context *, Strategy *);void (*executeStrategy)(Context *);
};// 上下文的构造函数
Context *context_new();//--- strategy.c ---
#include <stdio.h>
#include <stdlib.h>
#include "strategy.h"// 上下文的方法实现
static void setStrategy(Context *self, Strategy *strategy) {self->strategy = strategy;
}static void executeStrategy(Context *self) {if (self->strategy && self->strategy->execute) {self->strategy->execute(); // 委托给具体策略} else {printf("No strategy set.\n");}
}// 上下文构造函数
Context *context_new() {Context *ctx = (Context *)malloc(sizeof(Context));ctx->strategy = NULL;ctx->setStrategy = setStrategy;ctx->executeStrategy = executeStrategy;return ctx;
}//--- concrete_strategy_a.c ---
#include <stdio.h>
#include "strategy.h"// 具体策略A的实现
static void execute_a(void) {printf("Executing strategy A: Quick sort algorithm.\n");
}// 具体策略A的“构造函数”,创建一个策略对象
Strategy *strategy_a_new() {Strategy *s = (Strategy *)malloc(sizeof(Strategy));s->execute = execute_a; // 将函数指针指向具体实现return s;
}//--- concrete_strategy_b.c ---
// ... 类似地实现策略B
static void execute_b(void) {printf("Executing strategy B: Merge sort algorithm.\n");
}
Strategy *strategy_b_new() {Strategy *s = (Strategy *)malloc(sizeof(Strategy));s->execute = execute_b;return s;
}//--- main.c ---
int main() {Context *ctx = context_new();Strategy *strategyA = strategy_a_new();Strategy *strategyB = strategy_b_new();// 使用策略Actx->setStrategy(ctx, strategyA);ctx->executeStrategy(ctx); // 输出: Executing strategy A...// 动态切换为策略Bctx->setStrategy(ctx, strategyB);ctx->executeStrategy(ctx); // 输出: Executing strategy B...// 释放内存...return 0;
}

4、技术与内容

  • 技术: 使用结构体嵌套函数指针来模拟接口和多态。Context依赖于抽象的Strategy接口,而非具体实现。
  • 内容: 遵循开闭原则(对扩展开放,对修改关闭)。添加新算法(新策略)只需创建新的ConcreteStrategy,而无需修改Context的代码。常用于算法选择、文件格式转换、日志策略等场景。

模式二:观察者模式(Observer Pattern)

1、意图
定义对象间的一种一对多的依赖关系,当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。

2、UML图示

notifies
observes
Subject
-observers : List<Observer>
+attach(Observer*)
+detach(Observer*)
+notify()
ConcreteSubject
-state : int
+getState() : int
+setState(int)
«interface»
Observer
+update()
ConcreteObserver
-subject : Subject*
+update()

3、C代码实现(简化版)

//--- observer.h ---
typedef struct Observer Observer;
typedef struct Subject Subject;// 观察者接口
struct Observer {void (*update)(Observer *self, int state); // 通知函数
};// 主题基类
struct Subject {Observer *observers[10]; // 简单的观察者数组(实际应用可用链表)int count;void (*attach)(Subject *, Observer *);void (*detach)(Subject *, Observer *);void (*notify)(Subject *);
};//--- subject.c ---
#include "observer.h"
#include <stdio.h>static void attach(Subject *self, Observer *obs) {if (self->count < 10) {self->observers[self->count++] = obs;}
}
static void detach(Subject *self, Observer *obs) { /* ... 从数组中移除 ... */ }
static void notify(Subject *self) {for (int i = 0; i < self->count; i++) {if (self->observers[i] && self->observers[i]->update) {// 这里需要知道状态,通常ConcreteSubject会重写notify// 为了简化,我们假设传递一个虚拟状态值0self->observers[i]->update(self->observers[i], 0);}}
}// 主题的“基类”构造函数
Subject *subject_new() {Subject *sub = (Subject *)malloc(sizeof(Subject));sub->count = 0;sub->attach = attach;sub->detach = detach;sub->notify = notify;return sub;
}//--- concrete_subject.c ---
// 具体主题,拥有状态
typedef struct {Subject base; // 模拟“继承”,Base放在第一个成员,可以实现强制转换int state;
} ConcreteSubject;ConcreteSubject *concrete_subject_new() {ConcreteSubject *cs = (ConcreteSubject *)malloc(sizeof(ConcreteSubject));cs->base = *subject_new(); // 初始化基类部分cs->state = 0;return cs;
}
// 重写notify?或者提供setState方法,在setState中调用notify
void concrete_subject_set_state(ConcreteSubject *self, int state) {self->state = state;self->base.notify((Subject *)self); // 通知所有观察者
}//--- concrete_observer.c ---
typedef struct {Observer base;ConcreteSubject *subject; // 观察者需要知道它所观察的主题
} ConcreteObserver;static void update(Observer *self, int state) {ConcreteObserver *co = (ConcreteObserver *)self; // 获取包含自己的大结构体// 从主题获取真实状态int actual_state = co->subject->state;printf("Observer %p: Subject's state changed to %d\n", (void*)self, actual_state);
}ConcreteObserver *concrete_observer_new(ConcreteSubject *sub) {ConcreteObserver *co = (ConcreteObserver *)malloc(sizeof(ConcreteObserver));co->base.update = update; // 实现接口co->subject = sub;sub->base.attach((Subject *)sub, (Observer *)co); // 注册自己return co;
}//--- main.c ---
int main() {ConcreteSubject *subject = concrete_subject_new();ConcreteObserver *obs1 = concrete_observer_new(subject);ConcreteObserver *obs2 = concrete_observer_new(subject);// 改变主题状态,观察者会自动被通知concrete_subject_set_state(subject, 10);concrete_subject_set_state(subject, 20);return 0;
}

4、技术与内容

  • 技术: 使用组合函数指针。主题维护一个观察者列表。关键技巧是结构体嵌套ConcreteSubject包含SubjectConcreteObserver包含Observer)来实现一种形式的继承和向上转换。
  • 内容: 实现了发布-订阅机制,彻底解耦了主题和观察者。主题不知道观察者的具体类,只知道它们实现了Observer接口。广泛应用于GUI事件处理、数据监控、消息队列等。

模式三:单例模式(Singleton Pattern)

1、意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2、UML图示

Singleton
-static instance : Singleton*
-Singleton()
+static getInstance()
  • 私有构造函数防止外部new
  • 静态变量instance持有唯一实例。
  • 静态方法getInstance()控制实例的创建和访问。

3、C代码实现

//--- singleton.h ---
typedef struct Singleton Singleton;// 获取单例实例的全局函数
Singleton *singleton_get_instance(void);// 某个业务方法
void singleton_some_business_operation(Singleton *self);//--- singleton.c ---
#include <stdio.h>
#include <stdlib.h>// 定义单例结构体(可以包含各种数据)
struct Singleton {int some_value;// ... other data
};// 静态局部变量,在第一次函数调用时初始化,并持续存在
static Singleton *instance = NULL;Singleton *singleton_get_instance(void) {if (instance == NULL) {// 首次调用,创建实例instance = (Singleton *)malloc(sizeof(Singleton));instance->some_value = 42; // 初始化数据printf("Singleton instance created.\n");}return instance;
}void singleton_some_business_operation(Singleton *self) {printf("Singleton operation called. Value is %d\n", self->some_value);
}//--- main.c ---
int main() {// Singleton s; // 错误:结构体是不完整类型,无法在外部创建// Singleton *s = malloc(sizeof(Singleton)); // 可以但不合规,破坏了模式// 正确获取实例的方式Singleton *s1 = singleton_get_instance();Singleton *s2 = singleton_get_instance();if (s1 == s2) {printf("Both pointers point to the same instance.\n");}singleton_some_business_operation(s1);return 0;
}

4、技术与内容

  • 技术: 使用静态局部变量静态全局函数来控制实例的创建。通过不完整类型(在.h中只声明struct Singleton,在.c中才定义它)来实现信息隐藏,防止外部直接创建实例。
  • 内容: 确保一个类只有一个实例,并提供一个全局访问点。常用于需要全局管理的资源,如日志管理器、数据库连接池、应用程序配置等。注意多线程环境下的线程安全问题(上面的简单实现不是线程安全的)。

模式四:工厂方法模式(Factory Method Pattern)

1、意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

2、UML图示

creates
Creator
+factoryMethod() : Product
+someOperation()
ConcreteCreatorA
+factoryMethod() : Product
ConcreteCreatorB
+factoryMethod() : Product
«interface»
Product
+operation()
ConcreteProductA
+operation()
ConcreteProductB
+operation()
  • Creator:声明工厂方法,返回Product类型对象。
  • ConcreteCreator:重写工厂方法,返回一个具体的ConcreteProduct实例。
  • Product:工厂方法创建的对象接口。

3、C代码实现

//--- product.h ---
typedef struct Product Product;
struct Product {void (*operation)(Product *self);
};//--- creator.h ---
typedef struct Creator Creator;
struct Creator {// 工厂方法(函数指针),相当于一个“创建”接口Product *(*factoryMethod)(Creator *self);// 一个使用产品的操作void (*someOperation)(Creator *self);
};//--- concrete_creator_a.c ---
#include <stdio.h>
#include <stdlib.h>
#include "creator.h"
#include "product.h"// 具体产品A
typedef struct {Product base; // 模拟继承,使ConcreteProductA* 可被当作Product*char specific_data[20];
} ConcreteProductA;static void product_a_operation(Product *self) {ConcreteProductA *pa = (ConcreteProductA *)self;printf("ConcreteProductA operation: %s\n", pa->specific_data);
}// 具体创建者A
typedef struct {Creator base;
} ConcreteCreatorA;// 工厂方法的具体实现:创建ConcreteProductA
static Product *factory_method_a(Creator *self) {ConcreteProductA *prod = (ConcreteProductA *)malloc(sizeof(ConcreteProductA));prod->base.operation = product_a_operation;snprintf(prod->specific_data, 20, "Made by A");return (Product *)prod;
}ConcreteCreatorA *concrete_creator_a_new() {ConcreteCreatorA *ca = (ConcreteCreatorA *)malloc(sizeof(ConcreteCreatorA));ca->base.factoryMethod = factory_method_a;return ca;
}//--- main.c ---
// 客户代码只依赖于Creator和Product接口
void client_code(Creator *creator) {printf("Client: I'm not aware of the creator's concrete class.\n");Product *product = creator->factoryMethod(creator);product->operation(product);free(product); // 假设需要释放
}int main() {ConcreteCreatorA *creatorA = concrete_creator_a_new();client_code((Creator *)creatorA);// 未来可以轻松添加ConcreteCreatorB和ConcreteProductB// ConcreteCreatorB *creatorB = concrete_creator_b_new();// client_code((Creator *)creatorB);free(creatorA);return 0;
}

4、技术与内容

  • 技术: 核心是函数指针,它将对象创建的逻辑抽象成了一个接口(factoryMethod)。结合结构体嵌套,让具体的创建者决定创建何种具体的产品。
  • 内容: 遵循依赖倒置原则(依赖抽象,而非具体实现)。客户代码(client_code)只与Creator和Product的抽象接口耦合,不与任何具体类耦合。这使得系统易于扩展,添加新的产品类型只需增加新的ConcreteCreator和ConcreteProduct,而无需修改现有客户代码。
模式名称主要技术手段(C语言)核心思想与内容适用场景
策略模式结构体 + 函数指针(接口)分离算法,使其可独立变化和替换多种算法、策略可选的情况
观察者模式结构体嵌套 + 函数指针 + 链表/数组一对多的依赖关系,发布-订阅事件驱动系统、数据监控
单例模式静态局部变量 + 不完整类型(信息隐藏)控制实例数目,提供全局访问点全局资源管理器
工厂方法模式结构体嵌套 + 函数指针(工厂接口)将对象创建延迟到子类,解耦客户代码与具体类框架设计,需要创建可扩展的对象家族

在C语言中应用设计模式,更多的是学习其思想精髓而非机械照搬面向对象的实现。通过灵活运用结构体函数指针模块化编程等C语言核心特性,完全可以在过程式语言的范式中构建出灵活、可维护、可扩展的高质量代码架构。


文章转载自:

http://EKWGVide.ykgkh.cn
http://GtOV9D7r.ykgkh.cn
http://HndylkpE.ykgkh.cn
http://79HYA7KB.ykgkh.cn
http://jmq63hZf.ykgkh.cn
http://xg6wOWYJ.ykgkh.cn
http://4be5aEoZ.ykgkh.cn
http://f7t8l67N.ykgkh.cn
http://kPa9YOkt.ykgkh.cn
http://2ScoZlK8.ykgkh.cn
http://sZPrXk5Q.ykgkh.cn
http://U0in9Of9.ykgkh.cn
http://DE3mTfPR.ykgkh.cn
http://FBjup0Id.ykgkh.cn
http://1bBpbjWz.ykgkh.cn
http://OWAeIY9N.ykgkh.cn
http://aniDDisg.ykgkh.cn
http://vmqtxPgc.ykgkh.cn
http://FrXTha6q.ykgkh.cn
http://34SQncwL.ykgkh.cn
http://x3T25OQU.ykgkh.cn
http://LGH7Aqmm.ykgkh.cn
http://zckVRuqp.ykgkh.cn
http://2tDsjrWH.ykgkh.cn
http://JId7i1ja.ykgkh.cn
http://aOjGpIXH.ykgkh.cn
http://cndOAxYA.ykgkh.cn
http://bfSwPYSB.ykgkh.cn
http://yejdfAbn.ykgkh.cn
http://bvJRn0jD.ykgkh.cn
http://www.dtcms.com/a/373910.html

相关文章:

  • C++智能指针(先行版)
  • 安卓蓝牙文件传输完整指南
  • C++读文件(大学考试难度)
  • 拆解LinuxI2C驱动之mpu6050
  • Linux--线程
  • 中大型水闸安全监测的关键环节与措施
  • 基于QMkae/CMake配置QT生成的exe图标
  • 安科瑞电动机保护器:赋能化工冶炼行业高效安全生产的智能守护
  • 数据结构之链表(单向链表与双向链表)
  • 学习嵌入式的第三十五天——数据库
  • Coze源码分析-资源库-删除插件-后端源码-错误处理与总结
  • 中级统计师-统计法规-第一章 基本统计法律规范
  • 从日志到防火墙——一次“SQL注入”排查笔记
  • Java全栈开发面试实战:从基础到微服务架构
  • 《小小进阶:小型企业网规划组网与实现》
  • 深度学习——调整学习率
  • MySQL问题7
  • Sealminer A2 224T矿机评测:SHA-256算法,适用于BTC/BCH
  • windows下安装claude code+国产大模型glm4.5接入(无需科学上网)
  • C语言与FPGA(verilog)开发流程对比
  • 5G/6G时代的智能超表面:如何重构无线传播环境?
  • 【3D图像算法技术】如何对3DGS数据进行编辑?
  • Node.js对接即梦AI实现“千军万马”视频
  • Spring Boot Banner
  • 安卓端部署Yolov5目标检测项目全流程
  • 《2025年AI产业发展十大趋势报告》四十六
  • 《普通逻辑》学习记录——普通逻辑的基本规律
  • 彻底禁用 CentOS 7.9 中 vi/vim 的滴滴声
  • [C++刷怪笼]:AVL树--平衡二叉查找树的先驱
  • [概率]Matrix Multiplication