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

图解码说-六大设计原则(开闭原则、单一职责原则、里氏替换原则、接口隔离原则、依赖倒置原则、迪米特法则) - 详解

文章目录

      • ** 1单一职责原则 (Single Responsibility Principle, SRP)**
        • 示例1.1
        • 示例1.2
        • 示例1.3
      • **2 开闭原则 (Open/Closed Principle, OCP)**
        • 示例2.1
        • 示例2.2
        • 示例2.3
      • **3 里氏替换原则 (Liskov Substitution Principle, LSP) **
        • 示例3.1
        • 示例3.2
        • 示例3.3
      • **4 接口隔离原则 (Interface Segregation Principle, ISP)**
        • 示例4.1
        • 示例4.2
        • 示例4.3
      • **5 依赖倒置原则 (Dependency Inversion Principle, DIP) **
        • 示例5.1
        • 示例5.2
        • 示例5.3
      • **6 迪米特法则 (Law of Demeter, LoD) 或最少知识原则 **
        • 示例6.1
        • 示例6.2
      • **总结**
      • 参考

设计模式通常和面向对象编程相关,但C语言是过程式的,没有类的支持,C语言没有类,但可以通过结构体和函数指针模拟面向对象的概念。

** 1单一职责原则 (Single Responsibility Principle, SRP)**

  • 原话:There should never be more than one reason for a class to change
  • 本质:一个类应该只有一个引起它变化的原因,一个类只负责一个功能领域的职责,避免因一个功能修改影响其他功能。
  • 目的:降低耦合,提高内聚。当需求变化时,修改只影响少数模块,减少出错风险,易于理解和维护。
  • 举例:单一职责原则强调一个类只负责一个功能,这样修改一个功能时不会影响其他部分。如果违反这个原则,比如一个类同时处理用户认证和日志记录,当需要修改日志格式时,可能会意外影响到认证逻辑,导致bug。
  • 说明:利用功能抽象分类,一个类/模块/函数应该只负责一项职责,也就是只对一类行为负责,只要是能归结成一类的行为,都可以属于某个模块的功能,强调内聚性。这样修改时,只影响本模块,不影响其他已测试通过模块
  • 核心思想:一个类(在C中可能是模块或函数或结构体)应该只有一个引起变化的原因,即一个类只负责一项职
  • 在c语言中:强调每个结构体或函数应该只有一个职责
  • 关键点:拆分功能,一个函数只做一件事
示例1.1
//分离process_data和display_data职责,使得修改显示逻辑不会影响数据处理逻辑
// 数据处理模块
void process_data(int* data, int size) {for (int i = 0; i < size; i++) {data[i] *= 2; // 仅处理数据计算}
}
// 显示模块
void display_data(int* data, int size) {for (int i = 0; i < size; i++) {printf("%d ", data[i]); // 仅负责输出}printf("\n");
}
示例1.2
//分离save_to_file和process_data职责,使得修改保存逻辑不会影响数据处理逻辑,提高可维护性。
// 数据存储和数据处理分离
typedef struct {int id;char name[50];
} Data;
// 职责1:数据存储
void save_to_file(Data* data, const char* filename) {FILE* fp = fopen(filename, "w");fprintf(fp, "%d,%s", data->id, data->name);fclose(fp);
}
// 职责2:数据处理
void process_data(Data* data) {printf("Processing: %d - %s\n", data->id, data->name);
}
示例1.3

在这里插入图片描述

2 开闭原则 (Open/Closed Principle, OCP)

示例2.1
//新增排序算法只需实现SortAlgorithm接口,无需修改execute_sort函数
// 抽象接口
typedef void (*SortAlgorithm)(int*, int);
// 具体实现1:冒泡排序
void bubble_sort(int* arr, int n) { /*...*/ }
// 具体实现2:快速排序
void quick_sort(int* arr, int n) { /*...*/ }
// 客户端代码
void execute_sort(SortAlgorithm algo, int* arr, int n) {algo(arr, n); // 通过函数指针扩展算法
}
示例2.2
//新增策略只需添加新函数,不修改run_strategy
// 抽象策略
typedef struct {void (*execute)(void);
} Strategy;
// 具体策略A
void strategyA_execute() { printf("Strategy A\n"); }
Strategy createStrategyA() {return (Strategy){strategyA_execute};
}
// 具体策略B
void strategyB_execute() { printf("Strategy B\n"); }
Strategy createStrategyB() {return (Strategy){strategyB_execute};
}
// 上下文(无需修改)
void run_strategy(Strategy s) {s.execute();
}
示例2.3

在这里插入图片描述

**3 里氏替换原则 (Liskov Substitution Principle, LSP) **

示例3.1
//派生类结构体必须将基类作为第一个成员,通过强制类型转换实现多态
// 基类
typedef struct {int width;int height;
} Shape;
// 派生类(通过结构体包含实现继承)
typedef struct {Shape base; // 必须作为第一个成员int radius;
} Circle;
// 多态函数
void print_area(Shape* s) {// Circle可安全转换为Shape*使用printf("Area: %d\n", s->width * s->height);
}
示例3.2
//所有子类型(如减法)必须遵守基类约定
// 基类型
typedef struct {int (*calculate)(int, int);
} Calculator;
// 加法实现(子类型)
int add(int a, int b) { return a + b; }
Calculator createAddCalculator() {return (Calculator){add};
}
// 使用基类型接口
void calculate(Calculator c) {printf("Result: %d\n", c.calculate(5, 3));
}
int main() {Calculator adder = createAddCalculator();calculate(adder); // 输出8
}
示例3.3

在这里插入图片描述

4 接口隔离原则 (Interface Segregation Principle, ISP)

示例4.1
//读写操作分离为不同接口,客户端可仅实现需要的接口
// 分离的接口
typedef struct {void (*read)(void* data);
} Readable;
typedef struct {void (*write)(const void* data);
} Writable;
// 具体实现
typedef struct {Readable read_interface;Writable write_interface;
} FileHandler;
示例2,避免强制实现不需要的方法
// 细粒度接口1
typedef struct {void (*print)(void);
} Printer;
示例4.2
// 细粒度接口2
typedef struct {void (*scan)(void);
} Scanner;
// 实现分离
struct MultiFunctionDevice {Printer printer;Scanner scanner;
};
void print_impl() { printf("Printing...\n"); }
void scan_impl() { printf("Scanning...\n"); }
// 客户端按需使用
void client_printer(Printer p) {p.print(); // 不依赖scan
}
示例4.3

在这里插入图片描述

**5 依赖倒置原则 (Dependency Inversion Principle, DIP) **

示例5.1
//高层模块network_transmit不直接依赖具体设备,通过函数指针实现依赖注入
// 抽象设备接口
typedef struct {void (*send)(const char* data);
} Device;
// 具体实现
void wifi_send(const char* data) { /*...*/ }
Device wifi_device = {wifi_send};
// 客户端代码
void network_transmit(Device* dev, const char* data) {dev->send(data); // 依赖抽象接口
}
示例5.2
//notification依赖接口,与具体实现(Email/SMS)解耦。
// 抽象层
typedef struct {void (*send)(const char*);
} MessageService;
// 高层模块
void notification(MessageService service) {service.send("Hello DIP!");
}
// 具体实现
void email_send(const char* msg) {printf("Email: %s\n", msg);
}
MessageService createEmailService() {return (MessageService){email_send};
}
int main() {MessageService email = createEmailService();notification(email); // 依赖抽象接口
}
示例5.3

在这里插入图片描述

**6 迪米特法则 (Law of Demeter, LoD) 或最少知识原则 **

示例6.1
示例1,不直接访问结构体成员,
// 封装结构体细节
typedef struct {int internal_data;
} Module;
// 通过访问函数操作数据,通过专用函数进行数据操作
void module_set_data(Module* m, int val) {m->internal_data = val;
}
int module_get_data(Module* m) {return m->internal_data;
}
示例6.2
通过封装限制直接访问内部对象,降低耦合
typedef struct {char data[100];
} Database;
typedef struct {Database* db;// 封装间接访问const char* (*get_data)(struct DataFetcher*);
} DataFetcher;
const char* fetch_data(DataFetcher* fetcher) {return fetcher->db->data; // 避免直接暴露db结构
}
int main() {Database db = {"Secret Data"};DataFetcher fetcher = {&db, fetch_data};printf("%s\n", fetcher.get_data(&fetcher)); // 通过接口访问
}

总结

  • 结构体封装:用结构体+函数指针模拟对象
  • 函数指针:实现多态和接口抽象的核心手段
  • 模块化设计:通过文件分割实现高内聚低耦合
  • 内存管理:需特别注意手动内存管理带来的责任
  • 编译时多态:通过宏和函数指针组合实现

参考

【1】设计模式六大原则

【2】SOLID Principles: Object-Oriented Design Principles Explained

【3】SOLID principles. How to create maintainable code

【4】SOLID Principles with Real Life Examples

【5】SOLID Design Principles in Software Development

点击下面关注,获取最新最全分享,不迷路
http://www.jsqmd.com/news/323067/

相关文章:

  • 【游戏推荐】停车世界:建设与管理 (Parking World Build and Manage)免安装中文版
  • DeepSeek+豆包+Kimi降AI指令大全:配合工具效果翻倍
  • 基于深度学习YOLOv12的疲劳驾驶检测系统(YOLOv12+YOLO数据集+UI界面+登录注册界面+Python项目源码+模型)
  • 3款降AI率工具实测对比:9大平台验证谁能全过?
  • 8大AI场景+工具详解,从PPT到编程全方位提升工作效率(大模型入门指南)
  • 2026年知网AIGC检测不通过?用嘎嘎降AI三步搞定验证
  • 大数据领域数据网格:实现数据价值最大化的途径
  • 2026年免费降AI率工具推荐:研究生亲测这5款最靠谱
  • 【游戏推荐】房产达人2 单机+联机(House Flipper 2)免安装中文版
  • 基于深度学习YOLOv11的疲劳驾驶检测系统(YOLOv11+YOLO数据集+UI界面+登录注册界面+Python项目源码+模型)
  • 华为OD技术面真题 - JAVA开发 - 5
  • 比话降AI和嘎嘎降AI哪个好?花了200块测完结果意外
  • LangChain v1.0+ Model模块全解析:构建高效、灵活的大模型应用
  • Python实战:基于Playwright与异步技术的房产信息智能爬虫
  • 2026毕业论文降AI攻略:从90%降到10%的完整流程
  • 一款基于开源免费AI视觉平台的线下门店的用户画像系统
  • 2000-2024年上市公司融资约束数据SA WW KZ FC指数
  • 【Week6_Day27】【软件测试学习记录与反思】【阶段四 Python, 收集问题, 反思改进,写博客】
  • 2000-2024年上市公司平台生态嵌入程度数据+Stata代码
  • 寒假学习笔记1.27
  • 2017-2024年科技型中小企业名单数据
  • Python招聘信息聚合爬虫实战:使用Playwright与异步技术构建高效数据采集系统
  • Spark SQL与数据立方体:构建高效大数据分析平台
  • 爵士舞资源合集
  • 传感器数据助力大数据农业精准生产
  • 量化交易资源合集
  • Cursor@2.4.22基础设置
  • AI应用架构师:推动半导体良率AI预测的进步
  • 智能茶几:AI Agent的客厅使用模式分析
  • 宝藏指南!AI提示工程边缘计算优化,提示工程架构师指南