|
本帖最后由 tianheiGE 于 2017-4-8 23:03 编辑
编辑添加DirectFB介绍点击进入。
DirectFB学习之面向对象设计
前些日子读了《大话设计模式》一书受益匪浅,其中第五章举例的电脑容易修而收音机不容易修的例子让我印象深刻,它展开的一个设计模式——依赖倒转原则说明了抽象不应该依赖细节,细节应该依赖于抽象,即针对接口编程,不要对实现编程,这有利用程序的模块化和解耦合。如同在PC上不同的CPU、内存厂商多按照相同的接口来设计,从而非常容易的实现CPU或内存的更换操作,对于维修来说哪里坏换哪里就非常容易实现,然而对于收音机则被认为是一个典型的耦合过度的设计,要想修收音机则必须具备非常专业的知识。
由于此前我大多用C语言做程序设计,而用C语言开发大多被认为是面向过程化的程序设计,了解DirectFB后让我看到了用C语言做面向对象设计也可以如此优雅。
由下所示是DirectFB最终编译输出的到lib下的一个目录结构,这个也展示了DirectFB的组成部分。
├── directfb-1.4-5
│ ├── gfxdrivers
│ ├── inputdrivers
│ ├── interfaces
│ │ ├── IDirectFBFont
│ │ ├── IDirectFBImageProvider
│ │ └── IDirectFBVideoProvider
│ ├── systems
│ └── wm
1、gfxdrivers目录。它存放着图形加速器的drive,当你在编译DirectFB的时候如果没有配置图形加速器,即传入了--with-gfxdrivers=none参数,则这个目录不会生成,你也可以单独编译图形加速器drive并手动创建这个目录把生成的so放置到这个目录下,DirectFB启动的时候则会去检查这个目录并去加载它们。
2、inputdrivers目录。同理它是存放输入设备drive的目录,同样它存放的是so,并被自动的加载。
3、interfaces目录。它存放的是对第三方组件库的包装,即DirectFB在这里面去调用第三方库的,主要要有字体、图片和视频三大类。
4、systems目录。它存放着输出设备的drive,如fbdev、x11等。但DirectFB同时只支持一种输出,虽然它们多会被加载,指定输出设备可以在directfbrc中通过system=参数来指定,默认的它是通过fbdev来输出的。
5、wm目录。它则是存放个窗口管理子模块。
由上我们可以从DirectFB的编译输出中看出的模块结构,并且每个模块多被编译成了so的形式存在,而且还能在运行时被动态的加载,下面我们在代码中来看一下这些多是怎么来实现的。
DirectFB把各个子模块多编译成了so的形式从而可以实现子模块的动态切换,比如配置不同的system则使用对应的so即可,这个加载子模块是在lib/direct/modules.c文件中实现的,在各个子模块初始化的时候多会调用int direct_modules_explore_directory(DirectModuleDir *directory)函数将各个子模块目录的模块加载进来放到各自的链表里面,实际上它是调用的dlopen()函数来打开各个so的。
为什么各个so之间可以相互替换而不受影响呢,这就是得益于它们多是按照同样的接口进行设计的,这也是就是开头提到的基于接口的设计模式,让我们来举例看下其中systems子模块是如何按照接口进行设计的。
因为DirectFB是用C语言进行设计的,所以为了达到接口的效果,我们可以通过函数指针来实现,如下是要成为一个DirectFB中system需要实现的接口(它被定义在了src/core/system.h中):
- typedef struct {
- void (*GetSystemInfo)( CoreSystemInfo *info );
- DFBResult (*Initialize)( CoreDFB *core, void **data );
- DFBResult (*Join)( CoreDFB *core, void **data );
- DFBResult (*Shutdown)( bool emergency );
- DFBResult (*Leave)( bool emergency );
- DFBResult (*Suspend)( void );
- DFBResult (*Resume)( void );
- VideoMode* (*GetModes)( void );
- VideoMode* (*GetCurrentMode)( void );
- /*
- * Called at the beginning of a new thread.
- */
- DFBResult (*ThreadInit)( void );
- /*
- * Called upon incoming input events.
- * Return true to drop the event, e.g. after doing special handling of it.
- */
- bool (*InputFilter)( CoreInputDevice *device, DFBInputEvent *event );
- /*
- * Graphics drivers call this function to get access to MMIO regions.
- *
- * device: Graphics device to map
- * offset: Offset from MMIO base (default offset is 0)
- * length: Length of mapped region (-1 uses default length)
- *
- * Returns the virtual address or NULL if mapping failed.
- */
- volatile void* (*MapMMIO)( unsigned int offset,
- int length );
- /*
- * Graphics drivers call this function to unmap MMIO regions.
- *
- * addr: Virtual address returned by gfxcard_map_mmio
- * length: Length of mapped region (-1 uses default length)
- */
- void (*UnmapMMIO)( volatile void *addr,
- int length );
- int (*GetAccelerator)( void );
- unsigned long (*VideoMemoryPhysical)( unsigned int offset );
- void* (*VideoMemoryVirtual)( unsigned int offset );
- unsigned int (*VideoRamLength)( void );
- unsigned long (*AuxMemoryPhysical)( unsigned int offset );
- void* (*AuxMemoryVirtual)( unsigned int offset );
-
- unsigned int (*AuxRamLength)( void );
-
- void (*GetBusID)( int *ret_bus, int *ret_dev, int *ret_func );
- void (*GetDeviceID)( unsigned int *ret_vendor_id,
- unsigned int *ret_device_id );
- } CoreSystemFuncs;
复制代码
system.c中的所有实现则是依赖于这些接口。
下面我们来看一下一个具体的system的实现,如fbdev,它们位于systems/fbdev目录下,在fbdev.c文件开头处有如下代码:
- .............................
- #include <core/core_system.h>
- DFB_CORE_SYSTEM( fbdev )
- .............................
复制代码
我们把这两句代码展开会得到如下代码:
- .............................
- static CoreSystemFuncs system_funcs = {
- .GetSystemInfo = system_get_info,
- .Initialize = system_initialize,
- .Join = system_join,
- .Shutdown = system_shutdown,
- .Leave = system_leave,
- .Suspend = system_suspend,
- .Resume = system_resume,
- .GetModes = system_get_modes,
- .GetCurrentMode = system_get_current_mode,
- .ThreadInit = system_thread_init,
- .InputFilter = system_input_filter,
- .MapMMIO = system_map_mmio,
- .UnmapMMIO = system_unmap_mmio,
- .GetAccelerator = system_get_accelerator,
- .VideoMemoryPhysical = system_video_memory_physical,
- .VideoMemoryVirtual = system_video_memory_virtual,
- .VideoRamLength = system_videoram_length,
- .AuxMemoryPhysical = system_aux_memory_physical,
- .AuxMemoryVirtual = system_aux_memory_virtual,
- .AuxRamLength = system_auxram_length,
- .GetBusID = system_get_busid,
- .GetDeviceID = system_get_deviceid
- };
- __attribute__((constructor)) void directfb_fbdev( void );
-
- void
- directfb_fbdev( void )
- {
- direct_modules_register( &dfb_core_systems,
- DFB_CORE_SYSTEM_ABI_VERSION,
- fbdev, &system_funcs );
- }
- .............................
复制代码
由上可见我们要实现上面的函数接口,并且在这里生成了一个模块的注册函数,同时这个函数被赋予了constructor属性,这使得它成为so后被dlopen()函数打开的时候自动的去调用这个函数来完成这个模块的注册。
如果将上面的所述用UML类图来表示的话,它是如下这样:
由上可见非常符合面向对象的设计思路。同理其他子模块也是这样一个个被添加进来。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|