观察者模式(也叫做发布-订阅;源-监听器)
是什么?
--观察者模式定义了一种一对多的依赖关系,让多个观察者对象同事监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察着对象,使他们能够自动更新自己。
解决什么问题?
--在软件系统中常常要求某一个对象的状态发生变化时,某些其他的对象做出相应的改变。为了在设计上达到低耦合与代码的可复用性,那么设计人员要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足要求的最重要模式之一。
观察者模式的类型?
--观察者模式按照观察者对象的存储地点,分为两种:第一种是观察者对象存储在实际主题中;第二种是观察者对象存储在抽象主题中。(说明:这里所说的主题就是被观察者对象)
针对第一种举一个简单的事例,代码如下:
/**
* 抽象观察者只定义了一个更新自身的方法
* @author Administrator
*
*/
public interface Observer {
public void update();
}
/**
* 具体观察者A,当调用update方法时,会做出相应的更新
* @author Administrator
*
*/
public class ObserverA implements Observer{
private String name;
public ObserverA(String name){
this.name = name;
}
@Override
public void update() {
System.out.println(this.name+" updated ");
}
}
/**
* 抽象主题(抽象的被观察者)
* 此对象不存储观察者,具体的存储任务交给子类
* @author Administrator
*
*/
public interface Subject {
/**
* 给集合中添加一个观察者
* @param observer
*/
public void attach(Observer observer);
/**
* 从集合中删除一个观察者
* @param observer
*/
public void detach(Observer observer);
/**
* 通知所有的观察者更新自己
*/
public void notifyObservers();
}
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 具体的主题(具体的被观察者对象)
* 有存储观察者的集合(另一种观察者模式类型正是把对观察者对象存储在移至抽象主题中)
* @author Administrator
*
*/
public class ConcreteSubject implements Subject{
private Set<Observer> observerlist = null;
public ConcreteSubject(){
if(this.observerlist == null){
this.observerlist = new HashSet<Observer>();
}
}
@Override
public void attach(Observer observer) {
if(!observerlist.contains(observer)){
observerlist.add(observer);
}
}
@Override
public void detach(Observer observer) {
observerlist.remove(observer);
}
@Override
public void notifyObservers() {
if(observerlist !=null && observerlist.size()>0){
Iterator<Observer> iter = observerlist.iterator();
while(iter.hasNext()){
Observer ob = iter.next();
ob.update();
}
}
}
}
/**
* 客户端代码
* @author Administrator
*
*/
public class Client {
public static void main(String[] args){
//定义三个观察者和一个主题,把观察者存储在主题中
Observer ob1 = new ObserverA("xiao qiang");
Observer ob2 = new ObserverA("xiao ming");
Observer ob3 = new ObserverA("xiao jin");
Subject sub = new ConcreteSubject();
sub.attach(ob1);
sub.attach(ob2);
sub.attach(ob3);
//调用此方法,通知所有的观察者,更新自己
sub.notifyObservers();
System.out.println("------------");
//删除一个观察者,然后再次通知所有的观察者对象更新自身
sub.detach(ob1);
sub.notifyObservers();
}
}
观察者模式的另一种实现方式是把存储观察者的任务从具体主题移到抽象主题角色中,之所以能够这么做,是因为每一个具体主题角色都会定义一个存储观察者的集合,当主题角色的内部状态发生变化时,可以更新到集合中所有的观察者对象。既然所有的具体主题角色(抽象主题角色的子类)都会做这件同样的事情,那么我们就可以把它移到抽象主题角色中完成。此时的抽象主题角色需要用一个抽象类代替接口。
代码如下:
抽象观察者和具体观察者对象都不变,代码和上面的代码相同
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 抽象主题
* @author Administrator
*/
abstract public class Subject {
private Set<Observer> observerset = null;
/**
* 构造方法初始化集合
*/
public Subject(){
if(this.observerset == null){
this.observerset = new HashSet<Observer>();
}
}
/**
* 添加一个观察者
* @param ob1
*/
public void attach(Observer ob1) {
if(!observerset.contains(ob1)){
observerset.add(ob1);
}
}
/**
* 删除一个观察者
* @param observer
*/
public void detach(Observer observer) {
observerset.remove(observer);
}
/**
* 通知所有的观察者,更新自身
*/
public void notifyObservers() {
if(observerset !=null && observerset.size()>0){
Iterator<Observer> iter = observerset.iterator();
while(iter.hasNext()){
Observer ob = iter.next();
ob.update();
}
}
}
/**
* 返回一个遍历集合的引用
* @return
*/
public Iterator<Observer> getObservers(){
Iterator<Observer> iter = null;
if(observerset !=null && observerset.size()>0){
iter = observerset.iterator();
}
return iter;
}
}
/**
* 具体主题角色,由于把观察者集合的处理方法都移到抽象主题中,
* 所以具体的观察者中的方法变得很简单,可以专注于业务逻辑
* @author Administrator
*/
public class ConcerteSubject extends Subject {
//添加一个主题当前的状态
private String state = "";
//改变主题状态的同时通知所有的观察者对象
public void change(String state){
this.state = state;
System.out.println("state changed ==>>>"+this.state);
this.notifyObservers();
}
}
/**
* 客户端
* @author Administrator
*/
public class Client {
public static void main(String[] args){
//定义三个观察者和一个主题,把观察者存储在主题中
Observer ob1 = new ObserverA("xiao qiang");
Observer ob2 = new ObserverA("xiao ming");
Observer ob3 = new ObserverA("xiao jin");
ConcerteSubject sub = new ConcerteSubject();
sub.attach(ob1);
sub.attach(ob2);
sub.attach(ob3);
//调用此方法,通知所有的观察者,更新自己
sub.change("状态A");
System.out.println("------------");
//删除一个观察者,然后再次通知所有的观察者对象更新自身
sub.detach(ob1);
sub.change("状态B");
}
}
java语言对于观察者模式的支持
java语言的java.util库里面,提供了一个Observable类,以及一个Observer接口,构成java语言对于观察者模式的支持。
Observer接口中只定义了一个方法,即update(Observable o,Observer agrs)方法。当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用观察者对象的update(Observable o,Observer agrs)方法更新观察者自身。
被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observer方法非常重要:一个是setChanged(),另一个是notifyObservers()。第一个方法setChanged()被调用的时候,会设置一个内部标记变量,代表被观察者对象的状态发生变化。第二个是notifyObservers()被调用的时候,会调用所有登记过的观察者对象的update()方法,通知这些观察者对象更新自己。除此之外,Observable对象还有添加观察者对象addObserver(Observer o),删除观察者对象deleteObserver(Observer o)等方法,如果读者喜欢继续研究,可以去查看对应的java.util.*包下对应的类。
本文仅仅是自己的学习笔记。如果有错误请指正,谢谢!