设计模式~观察者模式
来源:互联网 发布:纽芬兰纪念大学知乎 编辑:程序博客网 时间:2024/05/21 06:28
观察者模式 Observer
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。
这个主题对象在状态上发生变化时,会通知所有观察者对象,让它们能够自动更新自己。
观察者模式的组成
抽象主题角色:把所有对观察者对象的引用保存在一个集合中,每个抽象主题角色都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
具体主题角色:在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个子类实现。
具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
程序实例
通过程序实例来说明观察者模式:
首先定义抽象的观察者:
//抽象观察者角色public interface Watcher{ public void update(String str);}
然后定义抽象的主题角色,即抽象的被观察者,在其中声明方法(添加、移除观察者,通知观察者):
//抽象主题角色,watched:被观察public interface Watched{ public void addWatcher(Watcher watcher); public void removeWatcher(Watcher watcher); public void notifyWatchers(String str);}
然后定义具体的观察者:
public class ConcreteWatcher implements Watcher{ @Override public void update(String str) { System.out.println(str); }}
之后是具体的主题角色:
import java.util.ArrayList;import java.util.List;public class ConcreteWatched implements Watched{ // 存放观察者 private List<Watcher> list = new ArrayList<Watcher>(); @Override public void addWatcher(Watcher watcher) { list.add(watcher); } @Override public void removeWatcher(Watcher watcher) { list.remove(watcher); } @Override public void notifyWatchers(String str) { // 自动调用实际上是主题进行调用的 for (Watcher watcher : list) { watcher.update(str); } }}
编写测试类:
public class Test{ public static void main(String[] args) { Watched girl = new ConcreteWatched(); Watcher watcher1 = new ConcreteWatcher(); Watcher watcher2 = new ConcreteWatcher(); Watcher watcher3 = new ConcreteWatcher(); girl.addWatcher(watcher1); girl.addWatcher(watcher2); girl.addWatcher(watcher3); girl.notifyWatchers("开心"); }}
实际应用在Java语言中:
EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。
Observer模式是比较常用的设计模式之一,虽然有时候在具体代码里,它不一定叫这个名字,比如改头换面叫个Listener,但模式就是这个模式。手工实现一个Observer也不是多复杂的一件事,只是因为这个设计模式实在太常用了,Java就把它放到了JDK里面:Observable和Observer,从JDK 1.0里,它们就一直在那里。从某种程度上说,它简化了Observer模式的开发,至少我们不用再手工维护自己的Observer列表了。不过,如前所述,JDK里的Observer从1.0就在那里了,直到Java 7,它都没有什么改变,就连通知的参数还是Object类型。要知道,Java 5就已经泛型了。Java 5是一次大规模的语法调整,许多程序库从那开始重新设计了API,使其更简洁易用。当然,那些不做应对的程序库,多半也就过时了。这也就是这里要讨论知识更新的原因所在。今天,对于普通的应用,如果要使用Observer模式该如何做呢?答案是Guava的EventBus。
EventBus基本用法:
使用Guava之后, 如果要订阅消息, 就不用再继承指定的接口, 只需要在指定的方法上加上@Subscribe注解即可。代码如下:
public class TestEvent { private final int message; public TestEvent(int message) { this.message = message; System.out.println("event message:"+message); } public int getMessage() { return message; }}
public class EventListener { public int lastMessage = 0; @Subscribe public void listen(TestEvent event) { lastMessage = event.getMessage(); System.out.println("Message:"+lastMessage); } public int getLastMessage() { return lastMessage; }}
public class TestEventBus { @Test public void testReceiveEvent() throws Exception { EventBus eventBus = new EventBus("test"); EventListener listener = new EventListener(); eventBus.register(listener); eventBus.post(new TestEvent(200)); eventBus.post(new TestEvent(300)); eventBus.post(new TestEvent(400)); System.out.println("LastMessage:"+listener.getLastMessage()); ; }}
//输出信息event message:200Message:200event message:300Message:300event message:400Message:400LastMessage:400
在项目中的具体应用:
package com.creditcloud.creditmarket.local;
public interface NotificationsHandler {
void run();
}
package com.creditcloud.creditmarket.local;
import com.creditcloud.creditmarket.constant.CreditMarketConstant;
import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;
import javax.annotation.PostConstruct;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@LocalBean
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class EmailLocalExecutor {
ExecutorService executorService;
@PostConstruct
public void init() {
executorService = Executors.newFixedThreadPool(CreditMarketConstant.NOTIFICATION_THREADPOOL_SIZE);
}
@Subscribe
@AllowConcurrentEvents
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void emailThreadPoolHandler(final NotificationsHandler handler) {
executorService.execute(new Runnable() {
@Override
public void run() {
handler.run();
}
});
}
}
appBean.getEmailEventBus().post( new NotificationsHandler() {
@Override
public void run() {
try {
//发送邮件:很高兴的通知您,您已预投标成功,中标总金额为%s,请在规定的时间内充值。
emailService.sendPreInvest(appBean.getClient(), email, name, amount);
} catch (Exception ex) {
logger.error("PreBid Email Sent to Investor Failed: email:{},userName:{}", email, name, ex);
}
}
});
- 模式设计:观察者模式
- 设计模式-----观察者模式
- 设计模式-观察者模式
- 设计模式--观察者模式
- 设计模式:观察者模式
- 设计模式-----观察者模式
- 设计模式:观察者模式
- 设计模式-观察者模式
- 设计模式 观察者模式
- 设计模式-观察者模式
- 设计模式-【观察者模式】
- 设计模式-观察者模式
- 设计模式 -- 观察者模式
- 设计模式-观察者模式
- 【设计模式】观察者模式
- 设计模式- 观察者模式
- 设计模式- 观察者模式
- 设计模式--观察者模式
- ubuntu 16.04 更新 gcc/g++ 4.9.2
- Moncler Herre face is evil to obtain
- 跳跃表原理
- javaWEB解决表单重复提交的问题(原理)
- SAP “在帐户分配中,请输入型煤的帐户分配数据” 错误可能原因
- 设计模式~观察者模式
- 第二章
- C#,大文件读取时快速定位,部分读取
- C语言标准库函数
- 解决android studio项目中Failded to sync Gradle project 'XXXX' Cause:failed to find target with hash strin
- 自定义自己的笔记本做WiFi热点
- oracle创建表空间
- 截图 将截图放入手机相册
- You must reset your password using ALTER USER statement before executing this statement.