基于OEA框架的客户化设计(三) “插件式”DLL
本篇主要描述GIX4项目中如何把单独的模块设计为一个“插件”,如何把它组装到系统中。至于为什么加引号,之后会有说明。
原理
在基于产品线开发时,7,2,1的产品功能分类中,20%的功能是需要在产品线主干中包含进来的。这些功能一般会被设计为“可选包”。在某一客户版本产品的装配阶段,在“可选包”集合中挑选需要的功能,进行组装,得到最终的产品。具体内容,见:《软件产品线工程方法:如何在OpenExpressApp做客户化工作》。
在基于OpenExpressApp框架的GIX4项目中,“合同”模块就是属于这20%的功能,它被设计为独立的DLL,在产品装配时为需要的客户进行装配。
DLL间的关系
项目中,实际的开发项目如下图:
图1 解决方案结构图
其中,红色区域的两个项目就是合同模块对应的实体类项目和WPF界面项目。它们都属于“产品721”中的“2”。(最上面的Customizing文件夹中的项目,都是属于各分支的客户版本独有的内容,属于“产品721”的中“1”。)合同包与主干包的关系如下:
图2 合同包与主干包的关系
合同模块中,带有合同信息的预算类ContractBudget从主干版本中的预算书类Budget中继承下来,作为新的聚合根对象(此概念,参见:《DDD》)。
动态加载DLL
在产品线工程的开发中,需要动态加载的DLL,是上述的“721”中的“2” 和“1”。
OEA框架中,使用MEF作为插件框架。(详见金根的:《.Net4下的MEF(Managed Extensibility Framework) 架构简介》)。所有DLL中,实现了IModule接口的
按照约定,把GIX4.Contract.Library.dll 和 GIX4.Contract.Module.WPF.dll 两个dll分别放置到Library和Module文件夹下,框架会自动加载所有的实体类型及其对应的元数据,并按照元数据的内容使用AutoUI模块进行展示。
客户特定的模块,则需要放置在客户各自的文件夹中。这在《基于OEA框架的客户化设计(一) 总体设计》中已经谈过。框架会根据当前的产品定义,进行DLL加载。
把合同包放到项目指定的文件夹中后,按照OEA框架中的元数据信息进行标注的聚合根对象,都会显示在左边的模块列表中,在合同模块中,包含了以下几个根对象:合同模板、合同科目、合同预算导入、合同经济指标。运行界面如下图:
图3 加入合同模块后的软件运行界面
自定义视图
一个独立模块的设计,不会考虑用户是否真的需要其所有的功能。在把它组装进产品后,很可能需要对它进行一些定制。例如,在合同模块的DLL放到产品中后,框架自动加载所有类型并显示,这就导致现在的ContractBudget类和原有的Budget类同时显示出来了。这里我们其实是要用ContractBudget完全替换Budget类,所以,我们需要在产品定义中,把Budget类完全隐藏:
1 2 3 4 5 6 7 8 9 | protected override UIInfo DefineUI() { var ui = base .DefineUI(); ui.Entity<Budget>().UnVisible(); ui.Entity<ContractBudget>().Visible(); return ui; } |
可以看到,这个定义是直接依赖了合同模块DLL的,也就是说,合同模块不是真的插件,而是在产品编译期已经知道必须包含这个DLL。所以目前只是做到编译期选择装配,而不是运行时动态插入新的DLL,这就是为什么一开始说合同模块并不是真正的插件的原因了。
总结
到本篇为止,客户化的内容已经基本说明。一些其它的问题为以单独的文章说明(例如:实体类继承方式的重构),关注OEA的朋友可以继续关注一下。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)