设计模式的C语言应用-观察者模式-第四章
模式介绍:观察者模式(Observer)
观察者模式定义了对象之间的一对多依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。在这里,发生改变的对象称之为观察目标,而被通知的对象称之为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,所以么可以根据需要增加和删除观察者,使得系统更易于扩展。
图表 1观察者模式流程图
观察者模式在C语言里也是实现形式非常明显的模式。逻辑上和责任链模式最相近的一个设计模式为观察者模式。观察者模式和责任链模式的最大的差别在于,事件会被通知到每一个handler,而不是逐级处理。也不存在优先级的说法,也不会出现事件没有处理需要异常函数收尾。一个Observer是否注册和执行不应该影响其他的Observer。而在责任链模式上,前面的责任handler在传递给下一个handler时,是可以改变事件相关变量。
但是在C语言实现上,观察者模式的handler绝大部分也是按照链表来组织的,在代码执行上,实际上相当于遍历链表。和责任链模式的区别在于每个handler没有优先级,没有权力决定是否停止遍历,最后事件也不需要被handler消费掉,也就是没有异常函数。
所以从C语言代码实现上讲,观察者模式可以看作责任链模式的特例。
-
无优先级
-
不能修改随事件而来的变量。比如在netfilter使用责任链模式就修改了随事件而来的数据包。
-
每个handler/observer只能无条件把事件传给observer链表的下一个节点。
图表 2观察者模式和责任链模式对比
左边是责任链模式,右边是观察者模式的内核代码实现流程。
观察者模式实现
观察者节点定义
//不需要处理结果
typedef int (*observer_func)(char *buf);
struct observer_ops_node {
struct list_head list; //内核链表标准结构 observer_func *handler; //handler的回调函数,没有优先级
};
观察者链和处理函数
//全局的观察者链
struct list_head observer_global_list;
//具体的处理函数
int observer_handler1(char *buf)
{
//do something return 0;
}
int observer_handler2(char *buf)
{
//do something return 0;
}
//封装成节点
struct observer_ops_node node1 =
{
.handler = observer_handler1,
}
struct observer_ops_node node2 =
{
.handler = observer_handler2,
}
注册和反注册函数
特别注意,一般是需要信号量锁定的,因为很可能链条上的函数正在执行。内核里喜欢用rcu锁,可以避免资源互斥引起cpu浪费。
int observer_register(struct observer_ops_node *node)
{
//lock observer_global_list //add node into observer_global_list //unlock observer_global_list return 0;
}
int observer_unregister(struct observer_ops_node *node)
{
//lock observer_global_list //delete node into observer_global_list //unlock observer_global_list return 0;
}
调用流程
不检查观察者结果,必须全部遍历完。
int main()
{
struct list_head *node; struct observer_ops_node *node_func; char buf[16]; observer_register(&node1); observer_register(&node1); //something happend, should trigger responsibility observer //fill buf with event list_for_each(node, &observer_global_list) { node_func = (struct observer_ops_node *)node; node_func.handler(buf); } return 0;
}
内核的观察者模式实现
观察节点模型
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *); //观察者回调函数 struct notifier_block __rcu *next; //链表结构 int priority; //优先级, 内核里这个属于扩展的用法。 };
下面的例子。
static struct notifier_block arp_netdev_notifier = {
.notifier_call = arp_netdev_event,
};
最后调用notifier_chain_register注册arp_netdev_notifier到netdev_chain链表上。
事件触发的处理函数
那么当网络接口状态发生变化时,就通过call_netdevice_notifiers(NETDEV_PRE_UP, dev);调用通知所有注册的observer回调函数。
函数简化如下。里面需要注意的只有一点,返回结果可能会有NOTIFY_STOP_MASK,允许某个observer停止遍历调用。从这个意义讲,observer既有优先级又能阻止调用,观察者模式和责任链模式的区别就很小了。
static int __kprobes notifier_call_chain(struct notifier_block **nl,
unsigned long val, void *v, int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE; struct notifier_block *nb, *next_nb; nb = rcu_dereference_raw(*nl); while (nb && nr_to_call) { next_nb = rcu_dereference_raw(nb->next); //取下一个observer ret = nb->notifier_call(nb, val, v); if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) break; nb = next_nb; } return ret;
}
模式实现总结
总体用法和责任链模式类似,而在内核里实现的观察者模式其实并没有那么“纯粹”,而是扩展了优先级特性和可停止特性。这个破坏了Observer之间的独立性,因为原则上,一个Observer是否注册和执行不应该影响其他的Observer,内核的扩展这就使观察者模式变成了责任链模式模式。
来源:华为云社区 作者:lurayvis
作者:华为云
来源:CSDN
原文:https://blog.csdn.net/devcloud/article/details/95617082
版权声明:本文为博主原创文章,转载请附上博文链接!
- 浅学设计模式之观察者<Observer>模式及在android中的应用
- 设计模式在游戏中的应用--观察者模式(十)
- (C#)设计模式 之 观察者模式 (经典应用:猫叫,烧开水)
- 设计模式-观察者模式应用
- 设计模式实战应用之二:观察者模式
- 设计模式的C语言应用-访问者模式-第九章
- C语言设计模式:责任链、观察者和访问者
- 设计模式在C语言中的应用--读nginx源码
- 设计模式实战应用之二:观察者模式
- 设计模式在C语言中的应用--读nginx源码
- 设计模式实战应用之二:观察者模式
- 设计模式的C语言应用-非典型模式-第十章
- js设计模式之观察者模式的应用
- 观察者设计模式应用
- 设计模式在C语言中的应用--读nginx源码
- php设计模式之观察者模式的应用详解
- 设计模式在C语言中的应用--读nginx源码
- 自顶向下构建网站 第四章 对项目应用设计模式
- 设计模式在 TypeScript 中的应用 - 观察者模式
- 设计模式之观察者模式在Listview中的应用