设计模式初探-观察者模式(OBSERVER)又称发布-订阅(Publish-Subscribe)依赖(Dependents)

观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新,属于对象行为型模式。观察者模式在软件设计中很常用,比如经典的MVC模式,Model为目标类,View为观察者,Controller为更新管理器。首先更新管理器即控制器先将视图和模型建立关联关系,然后当模型数据改变时,这些改变会自动反映在视图上,从而达到了业务和显示分离的效果。Java默认支持观察者模式,AWT1.1之后版本,Servlet,SAX2的事件处理模型均为基于观察者模式的委托事件模型(Delegation Event Model或DEM)。在DEM模型里面,主题(Subject)角色负责发布(publish)事件,而观察者角色向特定的主题订阅(subscribe)它所感兴趣的事件。当一个具体主题产生一个事件时,它就会通知所有感兴趣的订阅者。观察者模式提供了一种将发布者与订阅者松散地耦合在一起的联系形式,以及一种能够动态地登记、取消向一个发布者的订阅请求的办法。

一、使用场景

1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面,将这两者封装在独立的对象中以使它们能够独立地改变和复用。

2、当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象及这些对象是谁。

3、建立链式触发机制,A影响B,B影响C,C影响D等等。

二、UML图

观察者模式uml

三、Java实现

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package study.patterns.observer;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.ArrayList;  
  5. import java.util.Date;  
  6. import java.util.List;  
  7. /** 
  8.  * 观察者模式 
  9.  * @author qbg 
  10.  */  
  11. public class ObserverPattern {  
  12.     public static void main(String[] args) {  
  13.         ClockTimerSubject timer = new ClockTimerSubject();//目标  
  14.         DigitalClock digital = new DigitalClock(timer);//观察者  
  15.         BigBenClock bigben = new BigBenClock(timer);//观察者  
  16.         TimerTask task = new TimerTask(timer);//定时任务  
  17.         task.start();//启动定时任务  
  18.     }  
  19. }  
  20. /** 
  21.  * 抽象目标类  
  22.  */  
  23. abstract class Subject{  
  24.     protected List<Observer> observers = new ArrayList<Observer>();  
  25.       
  26.     /** 
  27.      *  注册观察者 
  28.      */  
  29.     public void attach(Observer obs){  
  30.         observers.add(obs);  
  31.     }  
  32.       
  33.     /** 
  34.      * 删除观察者 
  35.      */  
  36.     public void detach(Observer obs){  
  37.         observers.remove(obs);  
  38.     }  
  39.       
  40.     /** 
  41.      * 通知观察者的抽象方法 
  42.      */  
  43.     public abstract void notifyObs();  
  44. }  
  45. /** 
  46.  * 具体目标类,每秒更新下自己的内部时间状态  
  47.  */  
  48. class ClockTimerSubject extends Subject{  
  49.     private String time;  
  50.       
  51.     /** 
  52.      * 具体通知方式,通知所有观察者 
  53.      */  
  54.     @Override  
  55.     public void notifyObs() {  
  56.         for(Observer obs : this.observers){  
  57.             obs.update(this);  
  58.         }  
  59.     }  
  60.   
  61.     /** 
  62.      * 更新time,并将改变通知给观察者 
  63.      */  
  64.     public void tick(){  
  65.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  66.         time = sdf.format(new Date());  
  67.         notifyObs();  
  68.     }  
  69.       
  70.     public String getTime() {  
  71.         return time;  
  72.     }  
  73.   
  74.     public void setTime(String time) {  
  75.         this.time = time;  
  76.     }  
  77. }  
  78. /** 
  79.  * 观察者抽象接口,只有一个update方法  
  80.  */  
  81. interface Observer{  
  82.     public void update(ClockTimerSubject subject);  
  83. }  
  84. /** 
  85.  * 钟表绘制接口 
  86.  */  
  87. interface Widget{  
  88.     public void draw();  
  89. }  
  90. /** 
  91.  * 数字钟表,具体观察者 
  92.  */  
  93. class DigitalClock implements Widget,Observer{  
  94.     private ClockTimerSubject subject;  
  95.       
  96.     /** 
  97.      * 初始化目标,并将自己注册到该目标的观察者列表中  
  98.      */  
  99.     public DigitalClock(ClockTimerSubject subject){  
  100.         this.subject = subject;  
  101.         this.subject.attach(this);  
  102.     }  
  103.       
  104.     /** 
  105.      * 先检查发出通知的目标是否为自己注册过的,是则响应  
  106.      */  
  107.     @Override  
  108.     public void update(ClockTimerSubject subject) {  
  109.         if(this.subject == subject){  
  110.             draw();  
  111.         }  
  112.     }  
  113.   
  114.     @Override  
  115.     public void draw() {  
  116.         System.out.println("电子闹钟为您报时:"+subject.getTime());  
  117.     }  
  118. }  
  119. /** 
  120.  * 大笨钟,具体观察者 
  121.  */  
  122. class BigBenClock implements Widget,Observer{  
  123. private ClockTimerSubject subject;  
  124.       
  125.     /** 
  126.      * 初始化目标,并将自己注册到该目标的观察者列表中  
  127.      */  
  128.     public BigBenClock(ClockTimerSubject subject){  
  129.         this.subject = subject;  
  130.         this.subject.attach(this);  
  131.     }  
  132.       
  133.     /** 
  134.      * 先检查发出通知的目标是否为自己注册过的,是则响应  
  135.      */  
  136.     @Override  
  137.     public void update(ClockTimerSubject subject) {  
  138.         if(this.subject == subject){  
  139.             draw();  
  140.         }  
  141.     }  
  142.   
  143.     @Override  
  144.     public void draw() {  
  145.         System.out.println("伦敦大笨钟为您报时:"+subject.getTime());  
  146.     }  
  147. }  
  148. /** 
  149.  * 定时任务,每秒更新一次ClockTimerSubject的状态 
  150.  */  
  151. class TimerTask extends Thread{  
  152.     private ClockTimerSubject timer;  
  153.       
  154.     public TimerTask(ClockTimerSubject timer){  
  155.         this.timer = timer;  
  156.     }  
  157.   
  158.     @Override  
  159.     public void run() {  
  160.         while(true){  
  161.             try {  
  162.                 timer.tick();  
  163.                 Thread.sleep(1000);  
  164.             } catch (InterruptedException e) {  
  165.                 e.printStackTrace();  
  166.             }  
  167.         }  
  168.     }  
  169. }  
运行结果:

[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 电子闹钟为您报时:2014-02-12 21:44:48  
  2. 伦敦大笨钟为您报时:2014-02-12 21:44:48  
  3. 电子闹钟为您报时:2014-02-12 21:44:49  
  4. 伦敦大笨钟为您报时:2014-02-12 21:44:49  
  5. 电子闹钟为您报时:2014-02-12 21:44:50  
  6. 伦敦大笨钟为您报时:2014-02-12 21:44:50  
  7. 电子闹钟为您报时:2014-02-12 21:44:51  
  8. 伦敦大笨钟为您报时:2014-02-12 21:44:51  
四、模式优缺点

优点:

1、目标和观察者间的抽象耦合。目标仅知道它有一系列符合抽象接口Observer的观察者,而不知道这些观察者属于哪个具体的类,这样目标和观察者之间的耦合就是抽象的和最小的。

2、支持广播通信。观察目标会向所有已注册的观察者对象发送通知,具体如何处理通知由观察者决定,简化了一对多系统的设计难度。

缺点:

1、意外的更新。由于观察者仅仅知道目标改变了,而不晓得具体什么被改变了,目标上的一个看似无害的操作可能会引起一系列对观察者及依赖于这些观察者的对象的更新,导致错误的产生。


转载于:http://blog.csdn.net/qbg19881206/article/details/19132873

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Publish-Subscribe 模式通常使用观察者模式Observer Pattern)实现,观察者模式也被称为发布-订阅模式,是一种行为型设计模式。 以下是使用 C 语言实现的一个简单的 Publish-Subscribe 模式示例: ``` #include <stdio.h> #include <stdlib.h> #define MAX_OBSERVERS 10 /* 定义消息结构体 */ typedef struct { int data; } Message; /* 定义观察者结构体 */ typedef struct { void (*on_message)(Message); } Observer; /* 定义发布者结构体 */ typedef struct { Observer* observers[MAX_OBSERVERS]; int num_observers; } Publisher; /* 定义添加观察者函数 */ void add_observer(Publisher* publisher, Observer* observer) { if (publisher->num_observers < MAX_OBSERVERS) { publisher->observers[publisher->num_observers] = observer; publisher->num_observers++; } else { printf("Cannot add observer: maximum number of observers reached.\n"); } } /* 定义发布消息函数 */ void publish_message(Publisher* publisher, Message message) { int i; for (i = 0; i < publisher->num_observers; i++) { publisher->observers[i]->on_message(message); } } /* 定义观察者处理消息函数 */ void handle_message(Message message) { printf("Received message with data %d\n", message.data); } int main() { /* 创建发布者和观察者 */ Publisher publisher; Observer observer1 = { handle_message }; Observer observer2 = { handle_message }; /* 添加观察者到发布者 */ add_observer(&publisher, &observer1); add_observer(&publisher, &observer2); /* 发布消息 */ Message message = { 42 }; publish_message(&publisher, message); return 0; } ``` 以上代码定义了一个 `Publisher` 结构体作为发布者,一个 `Observer` 结构体作为观察者。发布者可以添加观察者,并通过 `publish_message` 函数发布消息。观察者在收到消息时会调用其自身的 `on_message` 函数处理消息。在 `main` 函数中,创建了一个发布者和两个观察者,并将观察者添加到发布者中。最后,发布发布了一条消息,观察者收到消息并处理。 ### 回答2: Publish-Subscribe模式采用的设计模式观察者模式观察者模式是一种行为型设计模式,用于定义对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,其所有依赖对象都会得到通知并自动更新。 以下是一个简单的C代码示例: #include <stdio.h> #include <stdlib.h> // 定义观察者接口 typedef struct Observer { void (*update)(struct Observer* observer, int data); // 更新方法 } Observer; // 定义具体的观察者 typedef struct ConcreteObserver { Observer base; // 继承自Observer接口 int id; // 观察者的ID,用于区分不同的观察者 } ConcreteObserver; // 更新方法的实现 void update(struct Observer* observer, int data) { ConcreteObserver* concreteObserver = (ConcreteObserver*)observer; // 将Observer类型转换为ConcreteObserver类型 printf("Observer %d received data: %d\n", concreteObserver->id, data); } // 定义发布者 typedef struct Publisher { Observer** observers; // 观察者数组 int numObservers; // 观察者数量 } Publisher; // 初始化发布者 void initPublisher(Publisher* publisher, int numObservers) { publisher->observers = (Observer**)malloc(sizeof(Observer*) * numObservers); publisher->numObservers = numObservers; } // 添加观察者 void addObserver(Publisher* publisher, Observer* observer, int index) { publisher->observers[index] = observer; } // 发布数据 void publishData(Publisher* publisher, int data) { for (int i = 0; i < publisher->numObservers; i++) { publisher->observers[i]->update(publisher->observers[i], data); // 调用每个观察者的更新方法 } } // 主函数 int main() { ConcreteObserver observer1 = {{update}, 1}; ConcreteObserver observer2 = {{update}, 2}; Publisher publisher; initPublisher(&publisher, 2); addObserver(&publisher, &(observer1.base), 0); addObserver(&publisher, &(observer2.base), 1); publishData(&publisher, 10); return 0; } 运行以上代码会输出: Observer 1 received data: 10 Observer 2 received data: 10 以上代码演示了一个简单的观察者模式的实现,其中发布者(Publisher)可以添加多个观察者(Observer),当发布发布数据时,所有的观察者都会收到通知并更新。 ### 回答3: Publish-Subscribe发布-订阅)模式采用的设计模式观察者模式(也称为发布-订阅模式)。 观察者模式是一种行为型设计模式,其中一个对象(称为主题或可观察者)维护其依赖对象列表(称为观察者),并在状态发生变化时自动通知观察者。这种模式使得主题和观察者之间的解耦,使得它们可以独立地进行更新。 下面是一个使用C语言的简单示例代码实现观察者模式: ```c #include <stdio.h> #include <stdlib.h> // 观察者接口 typedef struct Observer { void (*update)(struct Observer* self, int data); } Observer; // 具体观察者 typedef struct ConcreteObserver { Observer observer; } ConcreteObserver; void ConcreteObserver_update(Observer* self, int data) { printf("Received data: %d\n", data); } // 主题 typedef struct Subject { Observer** observers; int count; void (*attach)(struct Subject* self, Observer* observer); void (*notify)(struct Subject* self, int data); } Subject; // 具体主题 typedef struct ConcreteSubject { Subject subject; } ConcreteSubject; void ConcreteSubject_attach(Subject* self, Observer* observer) { self->observers[self->count++] = observer; } void ConcreteSubject_notify(Subject* self, int data) { for (int i = 0; i < self->count; i++) { self->observers[i]->update(self->observers[i], data); } } int main(void) { // 创建主题和观察者 ConcreteSubject subject; ConcreteObserver observer1; ConcreteObserver observer2; // 初始化观察者列表 Observer* observers[] = { &(observer1.observer), &(observer2.observer), }; subject.subject.observers = observers; subject.subject.count = 0; // 附加观察者到主题 subject.subject.attach(&(subject.subject), &(observer1.observer)); subject.subject.attach(&(subject.subject), &(observer2.observer)); // 通知观察者 subject.subject.notify(&(subject.subject), 42); return 0; } ``` 这个示例中,主题(ConcreteSubject)维护了一个观察者列表,可以动态地添加和删除观察者。观察者(ConcreteObserver)实现了观察者接口(Observer),在数据更新时会被主题通知。在示例代码的main函数中,创建了一个具体主题和两个具体观察者,然后将观察者附加到主题上并通知观察者。运行程序后,观察者将打印出接收到的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值