因为最近做的一个项目用到了观察者模式,所以就写一篇文章来记录下来吧~
首先观察者模式属于行为型模式,其意图是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。总的来说,观察者模式目的就在于解除耦合,依赖关系建立在抽象之上,耦合双发都依赖于抽象而不是依赖于具体,这也正体现了依赖倒置原则。
所谓观察者模式,首先我们需要的是观察者(Observer)和被观察者(Observeral Object),所以很自然的我们会想到先建立观察者相应的接口和被观察者相应的接口。现在以狗和小偷为例,小偷来偷东西,狗一叫小偷就被吓跑了,在这里狗是被观察者而小偷是观察者。接口如下:
小偷接口,听到犬吠就跑:
public interface IThief{
//update方法通过传递过来的object来做改变
public void update(String str);
}
小狗的接口,可以犬吠也会感到饥饿:
public interface IDog{
public void bark();
public void hungery();
}
这个时候我们已经有了观察者和被观察者这两个对象的接口,然而仅有着两个对象是不够的,还需要他们之间建立联系。
第一种方案是我们建立一个后台线程keep running,它的工作就是监视被观察者然后向观察者汇报。这样可以很容易的实现观察者模式,但是弊端在于这个线程要用一个死循环来不停监听。
第二种方案是将观察者聚集到被观察者类上,即在小偷实例中添加一个小狗对象,然后在相应的bark方法中调用小狗的update方法。但是这样也会带来问题,因为如果我们要增加一个甚至多个观察者类,比如主人Master,它观察到小狗饿了就会去喂它,或者我们要对被观察者的每个行为都进行观察,比如小狗饿的时候小偷就会扔点东西给它,然而我们现在这种设计修改起来将会比较麻烦,维护性上会有比较大的麻烦。
鉴于以上,我们采用第三种方案,增加一个Observable接口,所有的具体被观察者都需要实现这个接口,而每个具体观察者也都实现观察者接口Observer,如下:
public interface Observable{
//增加一个观察者
public void addObserver(Observer observer);
//删除一个观察者
public void deleteObserver(Observer observer);
//通知观察者
public void notifyObservers(String context);
}
public interface Observer{
//收到通知,做出改变
public void update(String context);
}
现在接口已经设计好了,那么我们就可以开始实现观察者模式了,设计三个类:小偷(Thief),小狗(Dog),主人(Master).
/**
* Class Dog implements the interface Observable
* in the methods bark() and hungery(), it notify the observers~
*/
class Dog implements Observable{
//List for the Observers~
private ArrayList<Observer> observerList = new ArrayList<Observer>();
//implement the method of the interface~
public void addObserver(Observer o){
if(o != null){
this.observerList.add(o);
}
}
public void deleteObserver(Observer o){
if(o != null){
this.observerList.remove(o);
}
}
public void notifyObservers(String context){
if(context != null){
for(Observer observer:observerList){
observer.update(context);
}
}
}
public void bark(){
System.out.println("bark~bark~bark~");
this.notifyObservers("bark");
}
public void hungery(){
System.out.println("Hungery~~~");
this.notifyObservers("hungery");
}
}
/**
* Class Thief implements the Observer interface
* When the context from dog is bark, thief just run away~
*/
class Thief implements Observer{
public void update(String context){
if((context != null)&&context.equals("bark")){
System.out.println("The dog is barking, run away~");
}
}
}
/**
* Class Master implements the Observer interface
* When the context from dog is hungery, the master just feed the dog~
*/
class Master implements Observer{
public void update(String context){
if((context != null)&&context.equals("hungery")){
System.out.println("The dog is hungery, I have to feed it~");
}
}
}
有了以上的实现,我们可以很容易的编写一个client来运行一下我们的观察者模式,如下:
public class Client{
public static void main(String[] args){
Observer thief = new Thief();
Observer master = new Master();
Dog dog = new Dog();
dog.addObserver(thief);
dog.addObserver(master);
dog.bark();
dog.hungery();
}
}
以上,我们自己实现了一个观察者模式,总的来说,观察者模式中有如下几个角色:
被观察者抽象:定义观察者必须实现的职责,一般为抽象类或者实现类,仅仅完成作为被观察者必须实现的几个方法,如添加观察者,删除观察者,通知观察者
观察者抽象:一般为接口,接收到消息就执行update操作,具体观察者实现该接口的update方法
具体被观察者:定义被观察者的业务逻辑,同时定义对哪些事件进行通知
具体观察者:定义接收到消息后具体的处理逻辑
通用代码如下:
//被观察者
public abstract class Observable{
private Vector<Observer> observerVec = new Vector<Observer>();//这里使用Vector因为Vector是线程安全的而ArrayList是线程异步,不安全
public void addObserver(Observer o){
this.observerVec.add(o);
}
public void delObserver(Observer o){
this.observerVec.remove(o);
}
public void notifyObservers(){
for(Observer o:this.observerVec){
o.update();
}
}
}
//观察者
public interface Observer{
public void update();
}
观察者模式的优点:
1.观察者与被观察者之间是抽象耦合,这样的话十分有利于扩展
2.建立了一套触发机制,形成了一个触发链
观察者模式的缺点:
1.开发效率和运行效率可能比较低
2.消息通知默认是顺序执行的,这样的话一个观察者卡住了,就会影响整体的效率,这样的情况下一般考虑异步方式
Java中的观察者模式:
JDK中实现了被观察者的抽象类java.util.Observable和观察者的接口java.util.Observer,java.util.Observable提供公开的方法支持观察者对象,最重要的两个方法是:setChanged()和notifyObservers(),setChanged()被调用后会设置内部的标记变量代表被观察者状态已经改变,这个时候才可以调用notifyObservers()来通知观察者,这样的话,上面的例子可以改为:
/**
* Class Dog extends the abstract class Observable
* Class Dog implements the interface IDog
* in the methods bark() and hungery(), it notify the observers~
*/
import java.util.Observable;
class Dog extends Observable{
public void bark(){
System.out.println("Bark~Bark~Bark~");
this.setChanged();
this.notifyObservers("bark");
}
public void hungery(){
System.out.println("Hungery~~~");
this.setChanged();
this.notifyObservers("hungery");
}
}
/**
* Class Thief implements the Observer interface
* When the context from dog is bark, thief just run away~
*/
import java.util.Observable;
import java.util.Observer;
class Thief implements Observer{
@Override
public void update(Observable o, Object arg) {
if((arg != null)&&arg.toString().equals("bark")){
System.out.println("The dog is barking, run away~");
}
}
}
/**
* Class Master implements the Observer interface
* When the context from dog is hungery, the master just feed the dog~
*/
import java.util.Observable;
import java.util.Observer;
class Master implements Observer{
@Override
public void update(Observable o, Object arg) {
if((arg != null)&&arg.toString().equals("hungery")){
System.out.println("The dog is hungery, I have to feed it~");
}
}
}
当然,java.util.Observable还实现了很多其他方法,具体可以参考JDK API,与本文的区别主要在于synchronized同步操作和一些异常判断而已。