C语言中的封装 - 答读者问

写C代码的时候,最头疼的事情是哪些信息要暴露给外界,哪些隐藏在模块自身。如果不能处理好封装,那么久而久之,代码就自然演进成互相缠绕的意大利面条。

比如说在一个ring buffer的基础上实现一个queue,我们可以提供 queue.h 暴露该模块的api,queue.c 进行具体实现,最基本的想法必然是:

queue.h

typedef struct {
    ring_buffer_t *ring;
    ...
    uint64_t counters[MAX_COUNTERS];
} queue_t;

int enqueue(queue_t *q, buf_t *buf);
buf_t *dequeue(queue_t *q);

然后在 queue.c 里面具体实现enqueue/dequeue。

这样做的坏处是,queue实现的细节被暴露给了调用者,只要调用者拿到了queue的pointer,就可以操作里面的ring,counters等等。如果queue模块本身没有提供充分的api,比如获取某个counter的信息,那么调用者可能就会图省事,自行做类似 q->counters[COUNTER_A] 这样的事情,从而完全破坏了模块的内聚。

更好的做法是使用 typedef 对类型做延迟定义。如下所示:

queue.h

typedef struct queue_s queue_t;

int enqueue(queue_t *q, buf_t *buf);
buf_t *dequeue(queue_t *q);

然后在 queue.c 里,真正去定义 struct queue_s

#include "queue.h"

struct queue_s {
    ring_buffer_t *ring;
    ...
    uint64_t counters[MAX_COUNTERS];  
}

这样,当你在该模块外的地方即使拿到了queue的pointer,也无法进行 q->counters[COUNTER_A] 这样的操作,编译器会报错:

error: dereferencing pointer to incomplete type

一开始使用这种方法定义数据结构会让自己或者别人写代码的时候很不舒服,因为拿到了一个pointer,却无法访问其内部的数据,是一种「很不C」的做法。这样会逼迫你写更多的代码,在需求不断变化(增加)的时候封装出来更多的api。而更多的api意味着更多的重构,以及更通盘地考虑设计上的优化。最终,模块的内聚大大加强,任何外部代码只能通过模块提供的api进行受限的操作,无法再像之前那样随心所欲了。

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2014-07-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互联网杂技

以后有机会写框架用得着的

在这个js框架随处乱跑的时代,你是否考虑过写一个自己的框架?下面的内容也许会有点帮助。 一个框架应该包含哪些内容? 1. 语言扩展 大部分现有的框架都提供了这部...

2745
来自专栏互联网杂技

如何去了解JavaScript引擎的工作原理

1. 什么是JavaScript解析引擎? 简单地说,JavaScript解析引擎就是能够“读懂”JavaScript代码,并准确地给出代码运行结果的一段程序。...

3867
来自专栏BeJavaGod

BeJavaGod - 如何正确使用数据字典进行分类统一操作(一)

先说说什么是数据字典,这个玩意一般不太会解释,举个栗子吧~ 每个系统都会有用户表,性别:男(1)女(0) 另外我们做物流的会涉及到车型:卡车(1),轿车(2),...

3447
来自专栏Crossin的编程教室

【Python 第45课】 查天气(3)

看一下我们已经拿到的json格式的天气数据: { "weatherinfo": { "city": "南京", "cit...

37411
来自专栏ytkah

帝国cms调用栏目自定义字段(栏目简介)如何操作

  开源的cms就像一个操作系统,可以满足大部分人的需求,如果你想增加一些特殊的功能,那就二次开发呗,就像APP一样。帝国cms默认的栏目是没有调用栏目自定义字...

4958
来自专栏Java技术栈

架构师必须掌握的 10 条设计原则

函数是程序员的工具中最重要的抽象形式。它们能更多地被重复使用,你需要编写的代码就越少,代码也因此变得更可靠。较小的函数遵循单一职责原则更有可能被重复使用。

1121
来自专栏小樱的经验随笔

CTF---Web入门第十题 Once More

Once More分值:10 来源: iFurySt 难度:易 参与人数:4782人 Get Flag:2123人 答题人数:2166人 解题通过率:98%...

3016
来自专栏程序员互动联盟

【编程技巧】提高程序员技能的11招

1.清晰的分析问题 2.三思而后行如何解决这个问题 3.收集完整的需求。 花点时间,想好产品的目标形态和最终的用户群。在这个阶段思路清晰会给以后节省很多时间。 ...

3497
来自专栏机器学习算法与Python学习

精选26个Python实用技巧,想秀技能先Get这份技术列表!

Python 虽然是脚本语言,但是因为其易学,迅速成为科学家的工具,从而积累了大量的工具库、架构,人工智能涉及大量的数据科学,用 Python 是很自然的事。磨...

1392
来自专栏专知

【干货】如何写代码 -编程内功心法

写代码就是学一门语言然后开始撸代码吗?看完了我的《GoF设计模式》系列文章的同学或者本身已经就是老鸟的同学显然不会这么认为。 编程是一项非常严谨的工作!虽然我们...

3438

扫码关注云+社区

领取腾讯云代金券