实例探索Java模式之路——观察者模式

来源:互联网 发布:易特进销存软件商贸版 编辑:程序博客网 时间:2024/05/22 17:28
观察者模式


1、观察者模式是对象的行为模式。又叫发布_订阅模式、源_监听模式等。

它定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象,当主题对象状态发生变化,会通知所有的观察者对象,使他们能够自动更新自己。


比如:当我做作业的时候告诉妈妈,饭做好了喊我吃饭。这里就是观察者模式,我向妈妈(系统主题)注册我感兴趣的事(吃饭),妈妈在事情发生的时候,通知系统观察者对象(我),做出相应的变化(去吃饭)。


2、观察者模式结构:




抽象主题角色:主题角色把所有观察者对象的引用保存在一个聚集里,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
抽象观察者:为所有具体观察者定义一个接口,在得到主题通知时更新自己,这个接口叫做更新接口。
具体主题角色:将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
具体观察者角色:存储与主题状态自恰的状态。


3、从具体主题指向抽象观察者的合成关系,代表具体主题对象可以含有任意多个抽象观察者对象引用。

抽象类不可能有实例,因此这些引用的真实类型必然为具体观察者类型,而这些引用的静态类型是抽象观察者类型。

这就意味着主题对象不需要知道引用了哪些具体观察者类型,而只知道抽象类型。



4、示意性是代码


//抽象主题角色
public interface Subject {
// 登记一个新的观察者
public void attach(Observer observer);


// 删除一个新的观察者
public void detach(Observer observer);


// 通知所有登记过的观察者
void notifyObserver();
}


import java.util.Enumeration;
import java.util.Vector;


//具体主题角色
public class ConcreteSubject implements Subject {


private Vector observerVector = new java.util.Vector();


// 登记一个新的观察者
@Override
public void attach(Observer observer) {


observerVector.addElement(observer);
}


// 删除一个新的观察者
@Override
public void detach(Observer observer) {
observerVector.removeElement(observer);


}


@Override
public void notifyObserver() {
Enumeration enumeration = observers();
while (enumeration.hasMoreElements()) {
((Observer) enumeration.nextElement()).update();


}


}


// 给出观察者聚集的Enumeration对象
private Enumeration observers() {
return ((Vector) observerVector.clone()).elements();
}


}


//抽象观察者
public interface Observer {


// 调用这个方法更新自己
void update();
}


//具体观察者角色
public class ConcreteObserver implements Observer {


@Override
public void update() {
System.out.println("我被唤醒更新!");
}
}


//客户端
public class client {
private static ConcreteSubject subject;
private static ConcreteObserver observer;


public static void main(String[] args) {
// 创建主题对象
subject = new ConcreteSubject();
// 创建观察者对象
observer = new ConcreteObserver();


// 将观察者对象登记到主题对象是上
subject.attach(observer);
// 改变主题对象通知观察者
subject.notifyObserver();
}
}


从上面我们可以发现,主题对象必须使用一个java聚集来维护一个对所有的观察者对象的引用。


如果把管理聚集的方法放到具体主题实现,那么每个具体主题都要把这个方法重新实现,代码就会冗余。我们把这些聚集的方法放在抽象主题中去,那么具体主题就变得很简单,只需要关系自己的业务逻辑即可。


所以修改如下:
import java.util.Enumeration;
import java.util.Vector;


//抽象主题角色
abstract public class Subject {
private Vector observerVector = new java.util.Vector();


// 登记一个新的观察者
public void attach(Observer observer) {


observerVector.addElement(observer);
System.out.println("add an observer");
}


// 删除一个新的观察者
public void detach(Observer observer) {
observerVector.removeElement(observer);
System.out.println("delete an observer");


}


public void notifyObserver() {
Enumeration enumeration = observers();
while (enumeration.hasMoreElements()) {
((Observer) enumeration.nextElement()).update();


}
}


// 给出观察者聚集的Enumeration对象
private Enumeration observers() {
return ((Vector) observerVector.clone()).elements();
}


}


//具体主题角色,只需要关系自己的业务逻辑
public class ConcreteSubject extends Subject {


private String state;


// 调用此方法更新主题状态
public void change(String newstate) {
state = newstate;
this.notifyObserver();
}
}
//客户端
public class client {
private static ConcreteSubject subject;
private static ConcreteObserver observer;


public static void main(String[] args) {
// 创建主题对象
subject = new ConcreteSubject();
// 创建观察者对象
observer = new ConcreteObserver();


// 将观察者对象登记到主题对象是上
subject.attach(observer);
// 改变主题对象通知观察者
subject.change("newstate");
}


}


5、观察者模式优缺点:

优点:
第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。

缺点:
第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。



通过此实例,相信对该模式有了进一步的认识。

每天努力一点,每天都在进步。


原创粉丝点击