观察者模式,又称发布-订阅模式、源-监听器模式和从属者模式。当一个对象的状态发生改变时,所有依赖它的对象均会接收到通知并被自动更新。
(1)目标与观察者的关系:一对多
(2)单向依赖:只有目标知道什么时候通知观察者
(3)命名模式:目标接口定义后面跟subject,观察者接口定义后面跟observer,观察者接口的更新方法建议为update,方法的参数是根据需要定义的。
(4)触发通知的时机:先改变后通知
(1)推模型:目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据。
(2)拉模型:目标对象在通知的时候只传递少量信息,如果观察者需要更具体的信息,由观察者主动到目标对象获取,相当于是观察者主动在目标对象中拉数据。
①“推”的方式是指,Subject维护一份观察者的列表,每当有更新发生,Subject会把更新消息主动推送到各个Observer去。
②“拉”的方式是指,各个Observer维护各自所关心的Subject列表,自行决定在合适的时间去Subject获取相应的更新数据。
所有的观察者都会直接得到全部的消息,并进行相应的处理程序,与主体对象没什么关系,两者之间的关系是一种松散耦合。
①实现了观察者和目标之间的抽象耦合。
②实现了动态联动。
③支持广播通信。
①如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
②如果观察者和观察目标之间有循环依赖,观察目标会触发它们进行循环调用,可能导致系统崩溃。
③观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
④如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
一个商家有一些产品和一些电商合作,每当有新产品时,就会把这些产品推送到电商,例如淘宝、京东等。
当我们关注了Wiki中感兴趣的人或事,我们这些关注者便会随时接收到变更消息。
去银行办理业务,当人多的时候,需要按顺序取号等待。直到银行叫到自己的号时,才轮到自己去进行办理。
当订单状态发生改变,即:关闭时,订单关联的工单和事件 ,便可以关闭了;否则 ,如果订单状态是开启的, 则不允许关闭对应的工单和事件。
一个商家有一些产品和一些电商合作,每当有新产品时,就会把这些产品推送到电商,例如淘宝、京东等。
①定义一个被观察者:产品列表ProductList,继承了Observable
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class ProductListSubject extends Observable {
private List<String> productList = null;//产品列表
private static ProductListSubject instance;//类唯一实例
private ProductListSubject() {}//构建方法私有化
/**
* 取得唯一实例
* @return 产品列表唯一实例
*/
public static ProductListSubject getInstance() {
if (instance == null) {
instance = new ProductListSubject();
instance.productList = new ArrayList<String>();
}
return instance;
}
/**
* 增加观察者(电商接口)
* @param observer 观察者
*/
public void addProductListObserver(Observer observer) {
this.addObserver(observer);
}
/**
* 新增产品
* @param newProduct 新产品
*/
public void addProudct(String newProduct) {
productList.add(newProduct);
System.err.println("产品列表新增了产品:"+newProduct);
this.setChanged();//设置被观察对象发生变化
this.notifyObservers(newProduct);//通知观察者,并传递新产品
}
}
②观察者1:淘宝商城TaoBaoObserver
import java.util.Observable;
import java.util.Observer;
public class TaoBaoObserver implements Observer {
@Override
public void update(Observable o, Object product) {
String newProduct = (String) product;
System.err.println("发送新产品【"+newProduct+"】同步到淘宝商城");
}
}
③观察者2:京东商城JingDongObserver
import java.util.Observable;
import java.util.Observer;
public class JingDongObserver implements Observer {
@Override
public void update(Observable o, Object product) {
String newProduct = (String) product;
System.err.println("发送新产品【"+newProduct+"】同步到京东商城");
}
}
④然后,测试代码:
public class ObserverTest {
public static void main(String[] args) {
ProductListSubject observable = ProductListSubject.getInstance();
TaoBaoObserver taoBaoObserver = new TaoBaoObserver();
JingDongObserver jdObserver = new JingDongObserver();
observable.addObserver(jdObserver);
observable.addObserver(taoBaoObserver);
observable.addProudct("新增产品1");
}
}
⑤最后,结果展示:
报社有新报纸后马上通知用户。
各个Observer维护各自所关心的Subject列表,自行决定在合适的时间去Subject获取相应的更新数据。
①自定义一个被观察者类Subject
public class Subject {
private List<Observer> observers = new ArrayList<Observer>();
public void attach(Observer observer){
observers.add(observer);
}
public void detach(Observer observer){
observers.remove(observer);
}
public void notifyObservers(){
for (Observer observer : observers) {
observer.update(this);
}
}
}
②继承自定义Subject,实现一个被观察者类
public class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
notifyObservers();
}
}
③自定义观察者接口Observer
interface Observer {
public void update(Subject subject);
}
④定义了观察者ConcreteObserver
public class ConcreteObserver implements Observer{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void update(Subject subject) {
System.out.println(name + "状态:" + ((ConcreteSubject)subject).getSubjectState());
}
}
⑤测试代码,定义了三个观察者
public class MainTest {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver();
observer1.setName("张三");
ConcreteObserver observer2 = new ConcreteObserver();
observer2.setName("李四");
ConcreteObserver observer3 = new ConcreteObserver();
observer3.setName("王二");
subject.attach(observer1);
subject.attach(observer2);
subject.attach(observer3);
subject.setSubjectState("看完报纸");
}
}
⑥测试结果
生产者:
public class ProducerFanout {
private static final String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
/** 1.创建新的连接 */
Connection connection = MQConnectionUtils.newConnection();
/** 2.创建通道 */
Channel channel = connection.createChannel();
/** 3.绑定的交换机 参数1交互机名称 参数2 exchange类型 */
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
/** 4.发送消息 */
for (int i = 0; i < 10; i++)
{
String message = "用户注册消息:" + i;
System.out.println("[send]:" + message);
//发送消息
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("utf-8"));
try {
Thread.sleep(5 * i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/** 5.关闭通道、连接 */
channel.close();
connection.close();
/** 注意:如果消费没有绑定交换机和队列,则消息会丢失 */
}
}
邮件消费者:
public class ConsumerEmailFanout {
private static final String QUEUE_NAME = "consumerFanout_email";
private static final String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
System.out.println("邮件消费者启动");
/* 1.创建新的连接 */
Connection connection = MQConnectionUtils.newConnection();
/* 2.创建通道 */
Channel channel = connection.createChannel();
/* 3.消费者关联队列 */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/* 4.消费者绑定交换机 参数1 队列 参数2交换机 参数3 routingKey */
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("消费者获取生产者消息:" + msg);
}
};
/* 5.消费者监听队列消息 */
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
短信消费者:
public class ConsumerSMSFanout {
private static final String QUEUE_NAME = "ConsumerFanout_sms";
private static final String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
System.out.println("短信消费者启动");
/* 1.创建新的连接 */
Connection connection = MQConnectionUtils.newConnection();
/* 2.创建通道 */
Channel channel = connection.createChannel();
/* 3.消费者关联队列 */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
/* 4.消费者绑定交换机 参数1 队列 参数2交换机 参数3 routingKey */
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
throws IOException {
String msg = new String(body, "UTF-8");
System.out.println("消费者获取生产者消息:" + msg);
}
};
/* 5.消费者监听队列消息 */
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
运行结果:
生产者
短信消费者
邮件消费者
观察者接口:Observer
public interface Observer {
void update(Observable o, Object arg);
}
被观察者类:Observable
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
/**
* Clears the observer list so that this object no longer has any observers.
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* Marks this Observable object as having been changed; the
* hasChanged method will now return true.
*/
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
/**
* Returns the number of observers of this Observable object.
*
* @return the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}
学习内容 | Java | Java | spring |
---|---|---|---|
第 一 周 | Java设计模式(5种)和排序算法(3种) | ||
第 二 周 | Java设计模式(5种)和排序算法(3种) | Java基础章节和集合部分,以及通过牛客网练习Java基础题 | |
第 三 周 | Java设计模式(5种)和排序算法(3种) | Java基础章节和集合部分,以及通过牛客网练习Java基础题 | 通过搭建maven项目,集成tomcat服务器,练习spring的常用注解以及xml方式 |