写在前面
写这篇文章的目的是为了本人练习框架开发做结构梳理,其主要中心思想就是去对象、去线程、(可能还有去终端);没有读过那么多专业的书籍,但毕业一年多也接触了不少代码,于是也想撸起袖子尝试着弄一弄,当然我还是个菜鸟,有说的不对的地方,路过的高手还请多多指教。另外这个设计没有考虑性能问题,主要是针对过程的管理,性能和算法应该纳入某一个过程的具体实现中去考虑,比如一个高并发服务线程就应该算一个单独过程,运行阶段时不应该频繁调用其他的过程。
中心思想
去对象
为什么使用计算机?是为了从输入得到某一种输出; 为什么要编程?是为了告诉计算机怎么得到这种输出; 为什么要定义类和函数?是为了分解从输入到输出的过程,使程序变得更直观简单; 既然要使程序变得简单,那何不更彻底一点,告诉计算机我想干嘛,然后计算机找到相应的过程(如果有的话)执行。 去对象,即有就执行。
去线程
开个玩笑:一个计算机可以跑多个程序。 事实上电脑上真正运行着的只有一个程序——操作系统。操作系统帮助我们隔离和整合了硬件资源,让我们不用从访问寄存器开始写程序,并为了更加合理有效地利用硬件资源,又抽象出了进程线程的概念,但对于写程序来说,属实不太友好,单片机程序好写多了,直接while for switch if else 组合拳。我发现对于异步的过程,非常需要像写单片机程序那样去写业务代码,一条完整的业务不应该被解耦,这会增加代码的阅读难度。 去线程,即维持异步业务的过程独立。
去终端
网络的作用是什么?连接多台计算机; 为什么要连接多台计算机?为了分享数据; 为什么要分享数据?为了节约时间, 网络是信息传递最快的方式了,通过数据耦合可以解决硬件异构和过程复用的问题;我并不关心过程的执行者是谁,我只关心结果。 去终端,即远程过程调用(RPC)。
实现历程
如何实现去对象
反射
可以利用Qt的元对象反射机制,元对象注册后在整个进程的生命周期中就和有了该类的构造器,通过类名即可创建对象,使用函数名即可调用到对应的函数,无需头文件,另外也可以和QML进行联动,我没看过Qt源码,但用脚都可以想到QML肯定也是用Qt的反射机制实现的。
序列化反序列化
QDataStream可帮助我们实现基本类型的序列化,自定义类型则需重载自定义类型的<< 和 >>运算符,序列化时存下元对象信息(自定义成员类名 标准类型成员值),反序列化我们实际上仅需要类名就能将对象创建成功,并使用所有基本参数的set方法将参数按顺序设入即可完成反序列化(在Q_PROPERTY中定义)。
对象集
通过对象名获得某个对象,对象集不允许跨线程访问(但当然支持movetothread),一切跨线程操作通过,qt信号通知完成,一个对象集中对象名重复时会自动析构之前的对象保持唯一性。
发布与订阅与调用
基于qt反射实现,发布即为向某个对象集注册某个对象的某个方法,订阅即观察某个对象集的某个方法是否被调用如果被调用则回调某个函数,调用则是通过注册名到用到对应的方法。
如何实现去线程
这里的去线程是指去掉不必要线程并不是不是使用多线程,该用线程池还得用线程池。 不知道是不是我的偏见,我觉得一个线程应该完成某一种特定的任务,就像某种设备只有特定的功能一样。 拿qt来说,主线程就只处理页面渲染和用户输入,跨线程直接操作UI是不被允许的。 但是qt中线程之间允许使用qt信号进行通信,就好比设备和设备之间可以通过连接串行总线来交互数据一样,这样一来便可以清晰画出线程之间的泳道图了。 单线程如何完成异步的业务呢,有两种方法。
信号和槽
第一种当然是qt特色的信号和槽 这种方法的缺点是代码可读性差,对于复杂的会话,在没有时序图的辅助下,很难直接从代码看明白会话流程。
协程
第二种方法当然就是协程(纤程)了,从一个协程函数中就能看明白整个异步流程,从哪里切出哪里又切入一目了然。
如何实现去终端
就是RPC,用什么暂时没想好,反正肯定不会自己写。
|