从操作系统内核看设计模式--linux内核中的Observer

来源:互联网 发布:中国自己的域名服务器 编辑:程序博客网 时间:2024/05/01 10:41

Linux虽然是面向过程的c语言写成的,但是却可以表达面向对象的思想,这个问题上,“语言是无关紧要的”,既然是一个语言,那么如果它是成功的,那么它就必须可以表达任何含义,因此软件设计思想和语言是无关的,总听见有人说用c语言无法写面向对象的程序,我无语!用c语言不但可以表达OO,而且可以表达任何的设计模式,这里设计模式和OO还有语言没有必然的关系,设计模式是一种大的框架性的理念,而OO是一种实现方式,至于或语言,那是更低层次的实现方式,据个例子,用中文可以写出一句话,如果用日文或者英文写不出同样含义的一句话,那么日文或者英文就是有缺陷的,现实证实它们没有缺陷,只是表达方式不同罢了,同样莎士比亚可以用英文写出名剧,用中文,李白可以写出妙诗,同样都是艺术作品。

linux中的观察者模式是最显然的了,就是“通知链”模型,在linux中,如果你想让自己的行为被别人注意到,那么你就要申请一条通知链,然后让所有关注你自己的实体注册到这条通知链上,最终的效果就是一旦发生一件值得关注的事情,所有的注册者都可以得到通知,想得到通知的实体注册代码如下:

int atomic_notifier_chain_register(struct atomic_notifier_head *nh, struct notifier_block *n)

{

unsigned long flags;

int ret;

spin_lock_irqsave(&nh->lock, flags);

ret = notifier_chain_register(&nh->head, n);

spin_unlock_irqrestore(&nh->lock, flags);

return ret;

}

static int notifier_chain_register(struct notifier_block **nl, struct notifier_block *n)

{

while ((*nl) != NULL) {

if (n->priority > (*nl)->priority)

break;

nl = &((*nl)->next);

}

n->next = *nl;

rcu_assign_pointer(*nl, n);

return 0;

}

以上的代码中atomic_notifier_chain_register的参数nh就是希望别人关注的实体申请的一条通知链,而参数n就是关注的实体注册的一个结构,该结构体包含了一个回调函数,一旦通知来临,该回调函数被调用。c语言中的回调函数其实和OO中的抽象类和接口中的抽象方法的意义是一样的,本质上就是一个接口,只是告诉调用方你只管调用就可以了,不必知道它的实现以及是否已经被实现,也不用管它到底做了哪些事,在观察者模式中,实际上解耦了通知者和被通知者,因此应用观察者模式可以得到两个好处,第一可以轻松实现框架的层次感,做到各司其职,第二就是可以合理安排对所在的层次,一个对象没有必要什么都管,这其实不是两个好处,而是一个好处的两个方面。这样我就可以独立的更改通知者的通知方式和被通知者得到通知的时候的反映方式。对于linux而言,主动通知的代码是以下:

int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls)

{

int ret;

rcu_read_lock();

ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);

rcu_read_unlock();

return ret;

}

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(*nl);

while (nb && nr_to_call) {

next_nb = rcu_dereference(nb->next);

ret = nb->notifier_call(nb, val, v); //调用观察者注册是回调函数

if (nr_calls)

(*nr_calls)++;

if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)

break;

nb = next_nb;

nr_to_call--;

}

return ret;

}

代码十分简洁,真的不错,我似乎看到了用c语言实现的Observer模式比OO语言实现的都好,OO中可以通过继承来实现通知-更新的统一化操作,比如所有的观察者继承于同一个抽象的观察者类,然后被观察者发出通知时就可以统一调用观察者抽象类对象的抽象接口了,而是对于c语言来说没有那么多的概念,但是从代码实现上看,更加简洁了,抽象类虽然没有,但是仍然不妨碍c语言组织子类,就是用一个链表,其实就是通知链,于是通知者根本不用管别的只需要调用一个函数就可以了,连什么抽象接口都不用调用,只要调用一个atomic_notifier_call_chain,并且知道通知链就可以了。

有人会说Observer模式和command模式是一样的,但是那只是看起来一样,它们的区别在于,command模式是一种比Observer模式确定的多的行为模式,在command模式中,命令的调用时期是确定的,双方都知道的,之所以用这个模式就是为了将命令的发出者和执行者之间解耦,但是对于Observer就不是这样的,观察者不知道什么时候以及什么情况下会的到通知。command模式更像是一个接力。

1 0
原创粉丝点击