您的位置:首页 > 编程语言 > Java开发

Java设计模式(6)之观察者模式学习总结

2017-10-28 11:20 681 查看
观察者模式:在观察者模式中,存在着对象之间的一对多的依赖关系,即一个对象的状态发生改变时,所有依赖于该对象的对象都会得到通知,并对自身的状态进行更新;
观察者模式的学习中,对象之间的一对多的依赖关系是学习观察者模式的切入点,而被依赖对象(目标对象)的状态改变会对依赖对象(观察者对象)状态产生影响是观察者模式的关键所在;只有对象之间形成一对多的依赖关系,才能实现被依赖对象与依赖对象之间的状态更新的交互作用;
生活中,其实存在很多观察者模式的应用场景,比如天气预报短信通知,当你在手机上开通了短信通知天气服务之后,每天你都会收到当天的天气信息的短信通知;再比如,你的手机上安装了腾讯体育APP,那么你只要接受该APP提供的推送即时消息通知的服务,那么一旦有更新的体育信息,将会向你的手机推送相关信息;
下面通过一个生活中的场景,进行相关的观察者模式设计代码:


package com.pattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 抽象目标类
* @author Administrator
*/
public  class Subject {
//订阅者列表,用于存放订阅者对象
private List<Observer> list = new ArrayList<Observer>();
//添加订阅者
public void add(Observer o)
{
list.add(o);
}
//删除指定订阅者
public void delete(Observer o)
{
list.remove(o);
}
//通知所有订阅者
public void notifyAllObservers()
{
for (Observer observer : list)
{
//将目标对象传入观察者对象的update方法
observer.update(this);
}
}
}

package com.pattern.observer;
/**
* 具体目标类
* @author Administrator
*/
public class WeatherSubject extends Subject {
//目标对象的状态信息
private String information;
public String getInformation()
{
return information;
}
//设置或更新目标状态信息
public void setInformation(String information)
{
this.information = information;
//更新状态信息后,调用通知方法,通知所有订阅者,使其进行各自的状态更新
this.notifyAllObservers();
}
}

package com.pattern.observer;
/**
* 观察者接口
* @author Administrator
*/
public interface Observer {
//更新观察者状态
public abstract void update(Subject subject);
}

package com.pattern.observer;
/**
* 具体观察者类
* @author Administrator
*/
public class ConcreteObserver implements Observer {
//观察者的名字
private String observerName;
//观察者的待更新状态信息
private String information;
//接收到信息后的响应信息
private String hint;

public ConcreteObserver(String name,String hint)
{
observerName = name;
this.hint = hint;
}

@Override
public void update(Subject subject)
information =((WeatherSubject)subject).getInformation();
System.out.println(observerName+"收到了"+information+"的通知"+","+hint);
}

}

package com.pattern.observer;
//测试类
public class TestObserverPattern {

public static void main(String[] args) {
//1.创建目标对象
WeatherSubject subject = new WeatherSubject();
//2.创建观察者对象
ConcreteObserver observerOne = new ConcreteObserver("Tom", "已收到,考虑是否去购物");
ConcreteObserver observerTwo = new ConcreteObserver("Jake", "已收到,考虑是否去旅游");
//3.添加观察者
subject.add(observerOne);
subject.add(observerTwo);
//4.更新目标状态信息
subject.setInformation("天气晴朗");
}
}


在设计观察者模式的时候,由于对于向观察者对象传送的消息内容的不同,观察者模式又分为推模型和拉模型;

拉模型:将目标对象传给观察者对象,观察者对象需要目标对象的哪一部分的状态信息,就通过该目标对象获取信息;当观察者对象对更新信息的需求发生变化时,拉模型可以很好地应对变化的场景;在上述的例子中,采用的是拉模型进行观察者模型的设计;

推模型:将指定的更新信息通知给观察者对象,当观察者对更新信息有了不同的要求之后,这种方式将会显得难以适应变化的要求;

如果想将上述例子通过推模型实现,只需要对具体观察者类中的update进行修改和对具体目标类中的notifyAllObservers进行重写;修改如下:

public void notifyAllObservers()
{
for (Observer observer : list)
{
//将传入观察者对象的update方法
observer.update(information);
}
}

public void update(String information)
{
this.information = information;
System.out.println(observerName+"收到了"+information+"的通知"+","+hint);
}

在Java中,其实提供了观察者模式的实现,利用java.util包下的Observable类和Observer接口就可以大大简化我们自己设计观察者模式的步骤;利用Java提供的观察者模式的实现将上述例子重新进行设计:


/**
*目标类的设计
*/
package com.pattern.observerInJava;
import java.util.Observable;

public class ConcreteSubject extends Observable
{
private String weatherInfor;//天气信息
public String getWeatherInfor()
{
return weatherInfor;
}
public void setWeatherInfor(String weatherInfor)
{
this.weatherInfor = weatherInfor;
//使用Java提供的观察者模式,在进行通知观察者更新信息之前所必需的一步
this.setChanged();
//设置拉模型,将目标对象直接传到观察者方法中
this.notifyObservers();
//设置推模型,将具体需要通知的信息传到观察着方法中
this.notifyObservers(weatherInfor);
}
}

/**
*观察者类的设计
*/
package com.pattern.observerInJava;
import java.util.Observable;
import java.util.Observer;

public class ConcreteObserver1 implements Observer
{
private String observerName;
private String weatherInfor;

public ConcreteObserver1(String name)
{
observerName = name;
}
@Override
public void update(Observable o, Object arg)
{
//采用拉模型进行观察者消息的更新
weatherInfor = ((ConcreteSubject)o).getWeatherInfor();
System.out.println(observerName+"从目标处拉取了更新的信息");
System.out.println(observerName+"收到了"+weatherInfor);
//采用推模型进行观察者消息的更新
System.out.println(observerName+"接收到了推动的更新的信息");
System.out.println(observerName+"收到了"+weatherInfor);
}
}

/**
*测试类的设计
*/
package com.pattern.observerInJava;
import com.pattern.observerInJava.ConcreteObserver1;
public class TestObserverInJava
{
public static void main(String[] args)
{
//1.创建目标对象
ConcreteSubject subject = new ConcreteSubject();
//2.创建观察者对象
ConcreteObserver1 observerOne = new ConcreteObserver1("Tom");
ConcreteObserver1 observerTwo = new ConcreteObserver1("Jake");
//3.添加观察者
subject.addObserver(observerOne);
subject.addObserver(observerTwo);
//4.更新目标状态信息
subject.setWeatherInfor("天气晴朗");
}
}


进一步地提出问题,当不同的观察者对象对目标对象的更新信息中感兴趣的方面不同,比如观察者对象A只对下雨天和阴天感兴趣,观察者对象B只对下雨天感兴趣,这时,将需要根据不同的需求向不同的观察者对象发送相应的更新信息;
这里可以使用面向接口编程的思想进行解决,设计一个抽象目标类,在该类中实现其具体实现类中公有的部分,而将notifyAllObservers方法放在其具体实现类中进行实现,在该方法中根据需求的不同进行不同的处理;
notifyAllObservers方法的具体实现可参考如下代码:
public void notifyAllObservers()
{
for (Observer observer : list)
{
//如果天气为下雨天,则只向观察者A、B推送更新信息
if("下雨天".equals(weatherInfor))
{
if(observer.getObserverName.equals("A"))
{
observer.update(this);
}
if(observer.getObserverName.equals("B"))
{
observer.update(this);
}
}
//如果天气为阴天,则指向观察者A推送更新信息
if("阴天".equals(weatherInfor))
{
if(observer.getObserverName.equals("A"))
{
observer.update(this);
}
}
}
}

在当自己进行观察者模式设计的时候,这里给出一些适用于观察者模式设计的注意点:
①命名上的建议:
目标接口定义为Subject
观察者接口定义为Observer
观察者接口中的的更新方法定义为update
②触发通知的时机应该在更新完目标对象的状态信息之后通知
③通知的顺序:观察者之间是平行的,在观察者模式中不需要指定通知的顺序
观察者模式设计流程分析:
准备阶段 1、创建目标对象 2、创建观察者对象 3、在目标对象中注册观察者对象
运行阶段 1、改变目标对象的状态 2、通知所有已注册观察者对象进行相应的处理 3、回调目标对象,获取相应数据

观察者优点及适用场景:
优点:
①观察者模式实现了观察者和目标之间的抽象耦合;
②观察者模式实现了动态联动;
③观察者模式支持广播通信;
使用场景:
①在一个业务场景中,某一方面的操作需要依赖另一方面状态的改变;
②在更改一个对象的状态同时,需要连带着修改其他对象的状态,并且需要被连带修改的对象的个数不知道;
③当需要实现通知对象和被通知对象之间的松散耦合的时候,选用观察者模式;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: