创建类设计模式:
- 单例模式、
- 工厂模式、
- 抽象工厂模式、
- 原型模式、
- 建造者模式
结构类设计模式
- 装饰器模式、
- 适配器模式、
- 门面模式、
- 组合模式、
- 享元模式、
- 桥梁模式
行为类设计模式。
- 策略模式、
- 责任链模式、
- 命令模式、
- 中介者模式、
- 模板模式、
- 迭代器模式、
- 访问者模式、
- 观察者模式、
- 解释器模式、
- 备忘录模式、
- 状态模式
linux 中的设计模式
-
模板方法(Template Method)
定义中间层,抽象出总线或者一类设备的接口 -
观察者模式
Linux内核中的通知链系统,callback函数 -
桥接模式(handle/body)
桥接模式的设计意图将抽象部分与它的实现部分分离,使它们都可以独立地变化。
Linux内核中使用的最重要的桥接模式,在于万物皆文件的思想。即将用户态的抽象字符设备文件,与实际的字符设备驱动实现分离,从而使得文件描述符和内核设备驱动可以分别在用户态和内核态独立变化,只需要在open的时候将抽象文件与实际的设备驱动关联起来即可。
-
Linux设备驱动中的继承关系
Linux内核设备驱动中,字符设备模型是典型的基类,而video_device、 framebuffer、miscdevice都是字符设备,满足IS-A的关系,因而都继承了字符设备的特性(支持字符设备open, ioctl, read,write等典型的访问方法函数), 都是字符设备的子类。
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
- 通过基类访问子类的方法
在Linux内核设备驱动中,我们在用户态open一个字符设备,然后调用字符设备的read/write/ioctl函数,最终也会调用到内核态设备驱动程序相应的read/write/ioctl函数的实现,从而模拟了通过基类与多态函数的特性来访问子类的目的。
实际上,Linux内核会维护基类与子类cdev对象实例的链表,当用户态发起read/write/ioctl等字符设备系统调用函数时,read/write/ioctl等字符设备系统调用函数会通过/dev/*下的字符设备,设备节点号的方式(主节点号major,次节点号minor)从cdev链表的子类中,找到对应子类的cdev对象实例,然后判断是否为空并调用子类cdev->ops->read/write/ioctl等实际子类的多态函数实现,从而最终实现了通过访问基类的多态函数,最终访问到子类实际的多态函数,这个面向对象的特性。
- 实例化:
大部分情况下,内核设备是通过总线的接口(包括platform虚拟总线,也包括USB、SPI、I2C等真正的总线,只要是继承structbus_type基类对象的总线都可以)的probe()函数进行实例化的。例如三星的framebuffer驱动s3c-fb.c,就是通过实现struct platform_driver这个接口,在接口的probe()函数中,为识别到的framebuffer设备创建/dev/*下的节点,实现s3c-fb字符设备的实例化。
在不实现总线接口的字符设备中,定义一个struct cdev mycdev;之后,在模块加载module_init()的时候,也是可以调用构造函数(初始化函数),创建/dev/*下的设备节点,从而完成实例化的。这种情况下,mycdev可以代表一个设备的实例,这种情况下模拟了面向对象设计模型中的单例模式,这也是可行的。