模式介绍:观察者模式(Observer)

观察者模式定义了对象之间的一对多依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。在这里,发生改变的对象称之为观察目标,而被通知的对象称之为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,所以么可以根据需要增加和删除观察者,使得系统更易于扩展。

图表 1观察者模式流程图

观察者模式在C语言里也是实现形式非常明显的模式。逻辑上和责任链模式最相近的一个设计模式为观察者模式。观察者模式和责任链模式的最大的差别在于,事件会被通知到每一个handler,而不是逐级处理。也不存在优先级的说法,也不会出现事件没有处理需要异常函数收尾。一个Observer是否注册和执行不应该影响其他的Observer。而在责任链模式上,前面的责任handler在传递给下一个handler时,是可以改变事件相关变量。

但是在C语言实现上,观察者模式的handler绝大部分也是按照链表来组织的,在代码执行上,实际上相当于遍历链表。和责任链模式的区别在于每个handler没有优先级,没有权力决定是否停止遍历,最后事件也不需要被handler消费掉,也就是没有异常函数。

所以从C语言代码实现上讲,观察者模式可以看作责任链模式的特例。

1. 无优先级

2. 不能修改随事件而来的变量。比如在netfilter使用责任链模式就修改了随事件而来的数据包。

3. 每个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 somethingreturn 0;}int observer_handler2(char *buf){//do somethingreturn 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_listreturn 0;}int observer_unregister(struct observer_ops_node *node){//lock observer_global_list//delete node into observer_global_list//unlock observer_global_listreturn 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 eventlist_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);  //取下一个observerret = nb->notifier_call(nb, val, v);if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)break;nb = next_nb;}return ret;}

模式实现总结

总体用法和责任链模式类似,而在内核里实现的观察者模式其实并没有那么“纯粹”,而是扩展了优先级特性和可停止特性。这个破坏了Observer之间的独立性,因为原则上,一个Observer是否注册和执行不应该影响其他的Observer,内核的扩展这就使观察者模式变成了责任链模式模式。

来源:华为云社区  作者:lurayvis

设计模式的C语言应用-观察者模式-第四章相关推荐

  1. c语言调试时出现的三种错误,C语言课件 第十四章 常见错误和程序调试

    <C语言课件 第十四章 常见错误和程序调试>由会员分享,可在线阅读,更多相关<C语言课件 第十四章 常见错误和程序调试(36页珍藏版)>请在人人文库网上搜索. 1.第十四章常见 ...

  2. 数据结构(C语言)第二版 第四章课后答案

    数据结构(C语言)第二版 第四章课后答案 1~5 B B C A B 6~10 B B C B B 11~15 A B D (C,B) C 1.选择题 (1)串是一种特殊的线性表,其特殊性体现在(B) ...

  3. c语言ppt课件循环语句,C语言循环语句课件四章.ppt

    <C语言循环语句课件四章.ppt>由会员分享,可在线阅读,更多相关<C语言循环语句课件四章.ppt(43页珍藏版)>请在装配图网上搜索. 1.循环结构,李晓玲,Page 2,本 ...

  4. c语言实验报告第四章答案,理工大学2010C语言实验报告参考答案

    理工大学2010C语言实验报告参考答案 2010C语言实验报告参考答案 实验一 熟悉C语言程序开发环境及数据描述 四.程序清单 1.编写程序实现在屏幕上显示以下结果: The dress is lon ...

  5. printf 指针地址_c语言入门 第十四章指针

    我们之前研究的数据类型, 语句, 函数等等,这些内容可以认为是编写程序的基础,除了c语言之外,在其他的编程语言当中也会有相似的内容 我们接下来要研究的指针,可以认为是c语言独有的特性,学会如何的使用指 ...

  6. 设计模式的C语言应用-访问者模式-第九章

    访问者模式(Visitor)介绍 把对象数据和操作分离,使操作可以独立演化.一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变.访问者模式是适用于那些数据结构比较稳定的模式.这个算是在C里面 ...

  7. 设计模式的C语言应用-状态机模式-第二章

    模式介绍 状态(state)模式是C语言实现相当常用的模式,也是能够在C语言***现出来的最显性的模式之一.在面向对象里,状态模式允许一个对象在内部状态改变的时候改变其行为. 状态用法很多,最常见的是 ...

  8. c语言作业答案第四章,C语言程序的设计课件源程序及习题的答案第4章.ppt

    C语言程序的设计课件源程序及习题的答案第4章 第4章循环结构的流程及应用 学习目标 ? 使用循环处理需要反复执行的操作. ? 循环结构的流程图. ? 循环与条件的综合应用. 学一学 while语句的一 ...

  9. 《Python语言程序设计》第四章(选择)学习笔记

    <Python语言程序设计>学习笔记 笔记选自<Python语言程序设计>[美]梁勇 著 本篇笔记没有记录用python绘画的turtle库 第4章 选择 可以使用int函数将 ...

最新文章

  1. Same binary weight (位运算)
  2. python代码规范快捷键_pycharm格式化代码 常用快捷键
  3. sort与sorted
  4. mongodb 导出到sqlserver_迁移sqlserver数据到MongoDb的方法
  5. 惊艳的cygwin——Windows下的Linux命令行环境的配置和使用
  6. 腾讯天津数据中心余热回收应用初探
  7. linux top交叉编译_Linux 系统下ARM Linux交叉编译环境crosstool工具
  8. c++11- Alias Template
  9. neo4j 迁移_在Kubernetes中迁移Neo4j图模式
  10. hdu 1233 最小生成树
  11. openfilename 选择文件夹_这个软件能帮你1秒内搜索文件夹中的东西
  12. 网络拓扑结构与静态特征
  13. 暴风影音“猝死” ,官网、APP全挂了!网友:我的青春说没就没了
  14. Win7 64bit IIS无法访问ACCESS数据库解决方案
  15. 信用卡欺诈检测建模分析
  16. python 刷票_Python刷票器的简单实现
  17. 网易云音乐(电脑版)网络连接不上,救命啊!!!
  18. deecamp考试题
  19. 搜狗新闻爬取怎么破解反爬机制呀,求指教
  20. 解决pycharm下载第三方库速度慢的问题

热门文章

  1. python classmethod函数_在python中使用与instance和classmethod相同的函数
  2. 长江浪花~朵儿朵尔朵
  3. 2、组件注册-@Configuration@Bean给容器中注册组件
  4. CentOS 7.2安装zabbix 3.0 LTS
  5. Eclipse:引用一个项目作为库(图文教程)
  6. matlab循环遍历数组_MatLab简易教程 #8 循环
  7. 动态规划——编辑距离
  8. 基础编程题目集 7-2 然后是几点 (15 分)
  9. 矢量归一化_7. 从矢量观测到姿态观测
  10. 多个python文件打包成exe_pyinstaller打包python文件成exe(原理.安装.问题)