设备驱动的设计不涉及复杂的技术应用,但是包括的内容比较多,关键是要考虑根据应用场景赋予设备驱动什么样的功能、特性、属性等。设备驱动接口一开始的设计中没有这么多内容,但会在应用过程中根据应用场景的需要而增加新的东西。所以说设计框架并不困难,重要的是把握大方向后逐渐完善细节。单一的技术都很简单,但是把众多简单的技术组装在一起就很有难度了。简单技术的不同组合,在不同的场景应用,效果也不一样。
接口可以把所需要的成员组合起来,封装成具有一定功能的集合。可以把它理解为一个模板,其中定义了一类对象的公共部分的动作、特性、反应等,分别对应面向对象编程中的方法、属性、事件等概念。抽象类或实体类可以继承接口完成对方法、属性和事件的特定响应,对事物进行具体的规范和多态的表述。
框架的设备驱动接口(IRunDevice)是软件框架与设备驱动之间的交互规范,是加载设备驱动(插件)的唯一入口,保证设备驱动能够在软件框架友好、稳定地运行。
IRunDevice有两个抽象类:RunDevice和RunDevice1,如图3-1所示。
图3-1 IRunDevice的两个抽象类
RunDevice和RunDevice1被定义为抽象类,是因为抽象类也是“接口”形式的一种,针对接口实现了设备驱动的方法、属性和事件,把必须实现的接口规定为抽象方法,把不是必须实现的扩展性接口规定为虚方法。软件框架只负责对外提供必要的接口,否则就破坏了框架本身的通用性。
所有的设备驱动(插件)可以继承这两个抽象类进行二次开发,特殊情况的设备驱动(插件)可以直接继承接口进行二次开发,但是不建议这样做,因为这需要二次开发者有较高的技术水平,能灵活掌握框架。
RunDevice是早期设计的抽象类,它本质上是一个自定义控件,起初的想法是把设备驱动插件设计成一个可显示的UI,可以在设备容器中随意拖动,并且设置相关的属性信息。但是,这会涉及一个问题,即可显示的自定义控件同时又是抽象类,那么在设计时将无法手动编辑UI界面,只能通过代码实现UI显示布局及内容,那么就失去了二次开发的快捷性、方便性。所以,RunDevice在代码上分成了Debug和Release两种模块,Debug用于开发、编辑模式,Release用于发布模式,具体如下。
即使这样也很不方便,所以就有了RunDevice1纯抽象类,把视图部分单独抽象出来一个接口,作为IRunDevice接口的属性。在框架中增加了一个IDeviceGraphics视图接口,代码如下。
RunDevice1抽象类实际上是继承了IRunDevice和IDeviceGraphics两个接口。
尽管IDeviceGraphics视图接口在框架内部并没有直接使用,但是在二次开发显示视图时会用到。另外,IDeviceGraphics视图接口具备继续扩展的余地,可以开发一个UI驱动管理器,专门进行UI布局、数据显示、属性设置及通过箭头对数据流向进行动态设置等操作。
原则上,在二次开发过程中继承RunDevice1抽象类完成设备驱动的开发,RunDevice不再继续提供接口服务。现在都是通过RunDevice1接口来完成驱动开发,具体接口定义见附录。