一起分析Linux系统设计思想——05字符设备驱动框架剖析(三)

在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的垃圾信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。

学习研究就是一个 清晰->凌乱->清晰… 的循环过程,符合 否定之否定 原理。因为好多知识之间都是有关联的,了解的少的时候觉得自己都明白了,但随着自己知识越来越多,又变得混乱起来(大部分人停留在这里就止步不前了),此时需要做的是了解更多的知识,然后梳理它们之间的联系,等某一天你突然搞懂了,就有一种豁然开朗,柳暗花明的感觉,此时就完成了一轮循环,功力提升了一个Level,接下来就是再次重复这个过程……

这一小节我们就是要把多个看似零散的知识串接起来,希望达到提纲挈领的效果。

3 Client-Server模型/生产者-消费者模型(接上篇)

上一篇我们讲到了 分层 的概念,在本篇我们要继续拆解这个概念,以便更好地理解和应用分层思想。

分层可以分为2层,也可以分为更多层(比如7层)。无论分多少层,相邻层之间的关系都遵循 双层模型 的特性——上层依赖下层,或者说下层服务于上层。对于多层来说,还存在 相对服务 的概念,比如第2层相对于第1层来说是被服务者,而相对于第3层来说是服务者。是不是和现实社会很相似?因为软件设计其实也是一门 仿生学 ,后面谈到面向对象你会更有感触。

我喜欢将复杂问题简化而不是反过来。而抓住主要矛盾提取共性往往是最有效的手法。

因此,我把网络中的 Client-Server模型生产者-消费者模型 全部归类到 双层模型 当中,核心思想就是 单向依赖 ,只不过是应用场景不同导致的细节实现不同而已,当然也就造就了多个不同的名字。

继续拆解,既然都出现 服务者被服务者生产者消费者 了,那么我们也不得不谈 面向对象编程思想 了。

对象是组成双层模型的基本元素。它是一个像人一样的个体。面向对象思想是软件设计“仿生”的一个里程碑。

3.1 面向对象编程

Linux系统中 一切皆文件 的背后是什么?是 高度抽象 。抽象的本质就是提取共性,进行统一。

就是抽象的产物,类本身就是抽象的,就好比打蛋糕的模具一样,它不是蛋糕,但可以打出蛋糕,因为它抽象出了蛋糕共有的特点。 对象 就是蛋糕了,是实际存在的。

对象由两部分组成:属性 + 行为 。属性为 ,行为为 ,动静结合这对象就活了。

对象的属性和行为其实就对应着 数据结构算法 。为什么说面向对象思想比较牛呢?因为面向对象更好地整合了数据结构和算法,整合的手段就是类,就是抽象。不管是自然语言、数学语言还是计算机语言,它们的本质就是将现实世界进行抽象。因为 抽象和分类是人类理解这个世界的基本能力

下面回归面向对象的三个重要特性进行进一步剖析。

3.1.1 封装

封装对于内部来说就是 打包 ,将属性和行为打包,将数据结构和算法打包,打包的好处就是方便管理。

封装对于外部来说,非常像 ,既是分割又是联系。分割是将外部和内部隔离成两个 ,而联系是像桥一样让外部有通道可以访问内部。

3.1.2 继承

继承就是为了 复用 。复用分为完全复用和部分复用。复用之后当然可以继续扩展新的特性。

而且,复用的重点一般是代码,而不是数据。因为差异往往体现在属性上,而不是行为上。也正是考虑到这个原因,程序员更应注重行为的抽象,将差异化尽量体现到属性当中,也就是数据当中。当这些数据以表格形式呈现时就是 表驱动 了。

3.1.3 多态和面向接口编程

多态是封装和继承的最终归宿。

多态就是为了 面向接口编程 ,面向接口编程才能产生多态效果——调用者调用的接口不变,但是内部实现可以改变(呈现多种形态)。那要怎么解释接口呢?结合封装里介绍的桥,简单来讲 不变的桥就是接口

多态的最大优点就是可以构建软件平台,也就是标准化。 标准化、平台化才能做大做强。

3.2 接口和依赖反转

正是因为 接口 的引入才使得 依赖反转 得以实现。才使得 关系流控制流 得以分离。所以说接口才是面向对象编程的精髓。

3.2.1 关系流和控制流

要讲清楚依赖反转,必须先搞清楚什么是依赖,什么是反转。

依赖比较容易理解,上一篇(https://albert-genius.blog.csdn.net/article/details/109733998)我们也提到了依赖。依赖是一种关系,我们把这种关系的层层传递称为 关系流

关系流其实是一种拓扑结构,分为节点和连线,普通节点包括 服务者被服务者 ,特殊节点包括 接口

那什么又是反转呢?要想理解反转,那必然要搞清楚不反转时是什么样子的。反不反转的参照物又是什么呢?

参照物是 控制流 。控制流简单理解就是调用关系的层层传递产生的“流”。

控制流也是一种拓扑结构,节点包括 驱动者(调用者/触发者)被驱动者(被调用者/被触发者) 。其中被调用者可以是功能模块的 实现者 ,也可以是 接口 。控制流的流动方向从驱动者指向被驱动者。

Tips:触发者和被触发者是为了完整性才放到这里的,属于事件触发层面的讨论,此处可以先跳过,不然容易增加负担。笔者准备在完成Linux内核驱动相关的专题之后写一个关于嵌入式架构设计思想的专题,到时候再掰开了,揉碎了分析诸如此类的概念。

我们先来看一下依赖未反转的情况是什么样的。如图1所示,关系流(绿色箭头)和控制流(紫色箭头)方向一致。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qDbatKNq-1606411662019)(05%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E5%89%96%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89.assets/image-20201127003129433.png)]

我们再来看一下依赖反转的情况。如图2所示,标有“实现依赖”的关系流和控制流(紫色箭头)方向刚好相反。

关系流与控制流逆向流动就叫做 依赖反转 现象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VB6aYDp0-1606411662021)(05%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E5%89%96%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89.assets/image-20201127004325492.png)]

依赖反转是如何做到的呢?就是因为引入了接口。引入接口,增加了“实现依赖”这种关系,因此才得以反转。

为什么要做这种反转?因为反转之后无论是服务者还是被服务者都依赖于接口,只要接口不变,依赖关系就保持稳定状态,无论是服务者还是被服务者的内部实现都可以随意改动,而不影响对方。

3.2.2 前调型依赖反转

如图2所示就是前调型依赖反转。

  • 特点:被服务者调用者(驱动者)服务者实现者(被驱动者)
  • 用途:可以做到底层变化对顶层变化不可见,从而实现底层平台化。

3.2.3 回调型依赖反转和注册机制

如图3所示就是回调型依赖反转。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-koZqhynQ-1606411662024)(05%E5%AD%97%E7%AC%A6%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%A1%86%E6%9E%B6%E5%89%96%E6%9E%90%EF%BC%88%E4%B8%89%EF%BC%89.assets/image-20201127010114722.png)]

通过与图2对比,我们发现只是将服务者与被服务者调换了位置而已,同样总结如下:

  • 特点:服务者调用者(驱动者)被服务者实现者(被驱动者)
  • 用途:服务者可以提供 “私人定制” 服务,因此可以构建灵活的可定制的业务支撑层。

谈到“私人定制”,这里不得不提的是 注册机制 ,因为实现“私人定制”的过程就是注册过程。

3.3 依赖反转的C语言实现

上面的概念适用于任何语言,但在C语言中是如何让上述概念落地的呢?C语言有两大杀手锏来模拟 接口 —— 钩子函数自定义段

3.2.2 函数指针

在C语言中使用函数指针来实现接口功能。我们把实现前调型依赖反转的接口/函数指针指向的函数体称为 前调函数 ;把实现回调型依赖反转的接口/函数指针指向的函数体称为 回调函数

3.2.3 自定义段

自定义段技术可以借助函数指针实现 隐式调用 ,能够在编译阶段完成函数指针的挂接,使用起来非常方便。

具体使用方法可以参看我之前写的一篇博客:基于自定义段技术构建指令系统_穿越临界点的博客-CSDN博客

本篇的概念梳理就酱了~~ 下一篇会用本篇的理论对字符设备驱动框架作一个360°扫描,让你彻底弄懂设计这个架构的人当时脑袋里到底在想什么,敬请期待~


恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~

已标记关键词 清除标记
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质? 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹?   那么C++就是你个人能力提升,职业之路进阶的不二之选。 【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 2.带你从知识与思想的层面从0构建C++知识框架分析大型项目实践思路,为你打下坚实的基础。 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署; 2.吊打一切关于C++的笔试面试题; 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块 基础篇 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 进阶篇 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 提升篇: 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页