前言

最近我们项目部的核心产品正在进行重构,然后又是年底了,除了开发工作之外项目并不紧急,加上加班时间混不够了....所以就忙里偷闲把整个项目的开发思路聊一下,以供参考。

鉴于接下来的一年我要进行这个主框架的开发,本着精益求精的态度,加上之前维护前辈的产品代码确实给我这个刚毕业的社畜带来了不小的震撼,我决定在这个模块的开发中优化之前的开发模式,提升整个产品的健壮性和独立性。

开发一个大型软件最重要的问题有三个,一是如何保证每个模块开发的独立性 二是如何保证数据结构的一致性 三是如何保证程序的可维护性和健壮性。这几个文章的内容我会在几篇文章中分开聊聊我的做法,做个记录。

本篇文章聊聊如何保证各个模块开发的独立性——怎么让功能模块、教学模块的开发独立于主框架本身。让不同的模块之间尽量通过接口的形式进行交互,而抛弃传统的中转消息码->调用模块的模式,让实际功能以接口形式暴露。

这一期简单聊聊开发准备,下一期浅谈怎么在开发中我们项目如何保证模块开发的独立性。

技术背景

请在阅读以下两篇文章之后观看本文以获得更佳的体验,以免你不知道我在说什么。

Qt开发Active控件:如何使用ActiveQt Server开发大型软件的主框架

Qt开发:Windows 下进程间通信的可行桥梁:窗体消息

【大型软件开发】浅谈大型Qt软件开发(一)开发前的准备——在着手开发之前,我们要做些什么?

为什么?

我们谈到为什么要这样开发的之前,要先聊聊之前我们的框架。

我们的软件之前没有框架,就是一个大的C#程序,然后里面想到什么就塞什么,然后教学模块、主框架、功能模块之间就通过一个C#事件委托向上传递。教学模块中没有办法直接引用所有的功能模块,而是通过一个函数里面传参,再转移到主程序中去。

这个模式本身是没有任何问题的,但是也可能是开发人员当时在开发的时候没有考虑过这个项目要维护十多年,导致整个程序在后面变成了一个几乎不可维护的庞然大物。

这里功能模块是几乎嵌死在主框架内的,这个是可以的,因为功能模块一般是调用外部的DLL或者对外部exe的管理,一般会和这些模块之间有深度的交互。而且一般我们也很少更新新的功能模块,光是现有的功能模块就几乎够了,之后的更新哪怕是直接嵌入在主框架内也是没有关系的。

当然了,功能模块也是一个个DLL,但是原先的调用是在使用的时候去尝试实例化一个功能类,然后再调用其中的方法。这样就涉及到调用、事件绑定等问题。

最严重的问题还是来自教学模块的信息向上传递。这个是由于引用导致的:

1.我们不可能让每个教学模块去引用各个功能模块,这样主框架完全脱离了教学模块的掌控,那相当于是每个教学模块重新开发了。而且每个功能模块并不能直接这样使用,需要的很多参数和消息都必须在主框架中获取或者初始化。比如座位信息,我们这个产品有一套很复杂的座位信息数据。还有一些比如MAC地址等。如果独立获取会极大的提升整个产品开发的维护难度和开发难度。

2.只能由框架去调用教学模块,这也就导致消息没法直接向上传递,只能通过类似回调函数的事件委托将事件以类似 key-value键值对的形式向上发送。这样我的主框架就要写一大堆if else去根据每个key去判断教学模块发这个消息想表达什么了。

我这里展示其中一部分就知道有多逆天了:



当然就像我说的,这是由于早期设计的时候完全没有考虑程序的拓展性开发所用的妥协性开发策略。在一开始确实方便而且好用。在后面这样一大坨if else让整个代码维护起来简直异常困难,更别提在接到消息之后这里还需要小小处理一下。

3.教学模块没法独立开发,必须依托于教师端。怎么说呢,就是教学模块几乎完全没法脱离教师端进行开发,因为要教学模块也需要暴露一大堆方法和接口供主框架去交互。模块设计操作起来就非常恶心了。

甚至!我们之前有过用exe的应用程序,所有的信息交互都是通过SendMessage进行的!你知道那对我幼小的心灵造成了多么大的伤害吗!这样的教学模块几乎是完完全全嵌在主框架内的专用exe,几乎不存在什么扩展性和维护性,因为除了问题除了开发者本人,别人根本没法改,也不知道怎么改。

或者我们换一种说法:教学模块这样设计就只能让主框架开发人员开发,且很难多个模块之间平行开发。

怎么做?

这就不得不提到面向未来的技术:COM组件

COM组件可以让主框架提供接口,然后各个教学模块就可以直接去调用主框架提供的接口。这样就直接替换掉了我上面说的if else判定这种僵硬的开发方式。

这个是ActiveQt Server向外公布的接口文档

这里提供的Public slots 就是主框架提供的方法。这样我们就可以通过直接调用接口的方式调用主框架内部的服务了。

也就是说框架实际上和之前的那个if else也差不多,区别就是主框架不需要在接收到消息之后进行检索,可以直接调用接口了。也就是说不需要维护那么长一条if else 链,而是暴露接口,管理接口即可~

就这样?当然不止,在这里我还提供了一个新的教学模块开发的范式。原来的教学模块 就像静态调用的DLL,而现在我们希望这个教学模块能像插槽一样即插即用。

该怎么做?既然是即插即用,那么就得请出我们的动态调用DLL 方法,接下来我将给出我的框架设计。

框架设计?

框架设计分为教学模块设计和主框架接口设计,这两部分实际上都是对主框架的设计,不过涉及的内容不一样。

教学模块框架

教学模块框架的涉及我需要给出一张图来做表示:

这个部分看图吧,我懒得解释太多了,这个图我觉得写的相当清楚了。

流程如下:

1.通过读取配置文件确定有哪些模块是可以尝试去调用的

2.在本地文件夹中检索可以调用的模块是否存在

3.调用教学模块约定好的方法来确定当前模块是否可用。

4.读取本地锁控,确定指定模块是否有锁控权限。

注1:因为是动态加载的DLL,那么DLL就必须提供类C接口,也就是extern "c" __del什么的,我忘了,反正就这么回事,自己百度查一下吧。

主框架的接口设计:

如图所示,我们在Interface_Kernel中提供了整个主程序中挂载的所有功能模块的单例调用接口,并在Interface_Kernel的单例中进行管理,然后再通过单例的方式直接向功能模块申请功能。这样既避免了大量重复啰嗦的消息码发来发去,也可以减少很多重复开发的工作量。

这样操作,主框架就不需要提供一个单独的类来管理教学模块和与教学模块进行交互了,而是可以只需要关心教学模块的启动、关闭、显示、隐藏 即可,其他的功能都由Interface_kernel单独交互即可。

这里我写了一个完整的工程,但由于代码是公司的财产,在此我不能开源所有的代码,如果你是将来维护开发的人员,你应该可以根据这篇博客了解到为什么主框架代码中会有接口类还有一个Interface_Kernel,原因也很简单,因为每次外部绑定主程序的时候,都会实例化一个新的接口,需要一个核心来管理所有的接口类实例。

至于说教学模块DLL的管理,也是类似的,但是这里就不展开细聊了。

总结

COM组件为功能模块的集中管理提供了可能,同时也为教学模块的独立开发提供了可能。

整个新框架和旧框架的核心思想区别就是:就框架把所有的教学模块都当成了主程序的一部分。

而新的框架中主程序其实只是为所有的教学模块提供各种各样的服务,比如语音、视频等服务,教学模块只需要调用指定的COM接口就可以直接调到主程序中的工具,而不需要再进行模块间的交互。而教学模块本身也只需要提供开启、关闭、显示、隐藏、认证五个接口,不需要再像之前一样写一大坨东西管理教学模块了。

这样既为后续模块化开发提供了更多的便利,也让主程序更加简洁,减少了很多不必要的重复开发。

如果有什么讲的不够详细的地方欢迎站内私信,我会尽量解答。

【大型软件开发】浅谈大型Qt软件开发(二)面向未来开发——来自未来的技术:COM组件。我如何做到让我们的教学模块像插件一样即插即用,以及为什么这么做。的更多相关文章

  1. [IC]浅谈嵌入式MCU软件开发之中断优先级与中断嵌套

    转自:https://mp.weixin.qq.com/s?__biz=MzI0MDk0ODcxMw==&mid=2247483680&idx=1&sn=c5fd069ab3f ...

  2. 浅谈大型web系统架构

    动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应用系统通常与数据库系统. ...

  3. 转:浅谈大型web系统架构

    浅谈大型web系统架构 动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应 ...

  4. 浅谈OA办公软件市场行情

    3.原文:http://www.jiusi.net/detail/472__776__3999__1.html 关键词:oa系统,OA办公软件 浅谈OA办公软件市场行情 中国的OA办公软件市场历经20 ...

  5. 【ZZ】浅谈大型web系统架构 | 菜鸟教程

    浅谈大型web系统架构 http://www.runoob.com/w3cnote/large-scale-web-system-architecture.html

  6. 浅谈关于QT中Webkit内核浏览器

    关于QT中Webkit内核浏览器是本文要介绍的内容,主要是来学习QT中webkit中浏览器的使用.提起WebKit,大家自然而然地想到浏览器.作为浏览器内部的主要构件,WebKit的主要工作是渲染.给 ...

  7. springboot开发浅谈 2021/05/11

    学习了这么久,本人希望有时间能分享一下,这才写下这篇浅谈,谈谈软件,散散心情. 这是本人的博客园账号,欢迎关注,一起学习. 一开始学习springboot,看了好多网站,搜了好多课程.零零落落学了一些 ...

  8. Android开发-浅谈架构(二)

    写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...

  9. Python测试开发-浅谈如何自动化生成测试脚本

    Python测试开发-浅谈如何自动化生成测试脚本 原创: fin  测试开发社区  前天 阅读文本大概需要 6.66 分钟. 一 .接口列表展示,并选择 在右边,点击选择要关联的接口,区分是否要登录, ...

  10. Android蓝牙开发浅谈(转)

    http://www.eoeandroid.com/thread-18993-1-1.html 对于一般的软件开发人员来说,蓝牙是很少用到的,尤其是Android的蓝牙开发,国内的例子很少     A ...

随机推荐

  1. Linux基础_7_文本显示

    注:实质是针对标准输出文本的各种骚操作! 简单查看 注:初略加工后进行显示. cat -n 文件名 #查看文件内容并显示行号 tac 文件名 #逆序查看 more 文件名 less 文件名 #按?搜索 ...

  2. 齐博x1 小程序与公众号长期永久订阅消息的申请方法

    要给用户发送消息提醒的话,需要申请订阅消息.订阅消息分一次性订阅与长期永久性订阅.一次性订阅没有实际意义,用户订阅一次就只能发送一次.这里主要是指导大家如何申请永久长期订阅功能.对于公众号而言,大家先 ...

  3. 3.版本穿梭&分支概述

    版本穿梭 如果我们提交了多个版本到本地仓库,想将工作区恢复到历史版本 可以先使用git reflog查看历史记录,获取到版本号 然后使用git rest --hard 版本号 命令恢复到指定版本 gi ...

  4. 从源码入手探究一个因useImperativeHandle引起的Bug

    今天本来正在工位上写着一段很普通的业务代码,将其简化后大致如下: function App(props: any) { // 父组件 const subRef = useRef<any>( ...

  5. [苹果APP上架]ios App Store上架详细教程-一条龙顺滑上架-适合小白

    如何在 2022 年将您的应用提交到 App Store 您正在启动您的第一个应用程序,或者距离上次已经有一段时间了.作者纸飞机@cheng716051来给你讲讲将应用程序提交到 App Store ...

  6. ML-朴素贝叶斯算法

    贝叶斯定理 w是由待测数据的所有属性组成的向量.p(c|x)表示,在数据为x时,属于c类的概率. \[p(c|w)=\frac{p(w|c)p(c)}{p(w)} \] 如果数据的目标变量最后有两个结 ...

  7. 云原生之旅 - 13)基于 Github Action 的自动化流水线

    前言 GItHub Actions是一个持续集成和持续交付的平台,能够让你自动化你的编译.测试和部署流程.GitHub 提供 Linux.Windows 和 macOS 虚拟机来运行您的工作流程,或者 ...

  8. .net随笔——Web开发config替换到正式config appSettings

    前言(废话) 查了一些资料,总体来说呢,就是坑,而且顺带吐槽下百度,一个内容被copy那么多遍还排在最前面.同一个内容我点了那么多次,淦. 正题: 实现目的:开发的时候使用system.debug.c ...

  9. swap,传参实质

    void swap(int a,int b){ int s=a; a=b; b=s; } int main(){ int x=1,y=2; swap(x,y); } 上面的函数并不能实现交换,因为传参 ...

  10. elasticsearch 之 histogram 直方图聚合

    目录 1. 简介 2. bucket_key如何计算 3. 有一组数据,如何确定是落入到那个桶中 4.需求 4.1 准备mapping 4.2 准备数据 5.histogram聚合操作 5.1.根据r ...