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

举报
lurayvis 发表于 2017/11/13 09:50:48 2017/11/13
【摘要】 设计模式的C语言应用-观察者模式... 1模式介绍:观察者模式(Observer) 1观察者模式实现... 3观察者节点定义... 3观察者链和处理函数... 3注册和反注册函数... 4调用流程... 4内核的观察者模式实现... 5观察节点模型... 5事件触发的处理函数... 6模式实现总结... 6模式介绍:观察者模式(Observer) 观察者模式定义了对象之间

设计模式的C语言应用-观察者模式... 1

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

观察者模式实现... 3

观察者节点定义... 3

观察者链和处理函数... 3

注册和反注册函数... 4

调用流程... 4

内核的观察者模式实现... 5

观察节点模型... 5

事件触发的处理函数... 6

模式实现总结... 6



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

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

image.png

图表 1观察者模式流程图

 

 

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

 

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

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

 

1. 无优先级

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

3. 每个handler/observer只能无条件把事件传给observer链表的下一个节点。

image.png

图表 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_notifiernetdev_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,内核的扩展这就使观察者模式变成了责任链模式模式。

 


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。