java 观察者模式

观察者模式定义了一个一对多的依赖关系,当被观察者(主题)更新时会自动更新观察者们。在观察者模式中,被观察者无需知道有哪些观察者在观察它,只是在发生变化的时候调用更新的方法即可;观察者无需知道具体观察了什么对象,只是在被调用更新方法时自动更新自己的信息即可。观察者模式最大的优点即在于此,通过松耦合达到了对象间信息的传递。无论是JDK源码还是各种框架应用都大量的使用了这个模式。

观察者模式流程:

  1. 创建主题接口,主题接口是所有被观察者要实现的接口,主题接口中含有:添加、删除、更新三个方法,用于维护观察者列表。

  2. 创建被观察者接口,被观察者接口中只有一个更新方法,所有的被观察者都需要继承这个接口,用于实现更新方法,这个更新方法也是被观察者会调用的列表中的观察者的方法。

  3. 实现主题接口创建被观察者,作为一个合格的被观察者必须实现主题接口,实现三个方法,并且在该类中要维护一个列表,该列表中存放所有的观察者。增添方法将参数观察者传入列表中,删除方法即删除列表中的观察者,更新方法即调用列表中所有的观察者的更新方法。

  4. 实现观察者接口创建观察者,该观察者具备更新方法以供被观察者调用。在构造器中传入被观察者参数,并且直接用该参数调用添加方法添加该观察者至被观察者的列表中。并且该观察者中存有被观察者类型的引用,将上面参数的引用留下,以便以后删除方便。

  5. main方法中创建被观察者,再创建观察者,将被观察者当作参数传入观察者实例中。这样就建立起了两个对象间的关系,当被观察者被改变时,观察者自动更新。

观察者模式技巧:

  1. 推与拉
    a) 观察者模式有推与拉两种情况。在上述的过程中,我们将被观察者整个对象作为参数传入了观察者中。这样有两个问题,第一个问题不安全,观察者可以通过这个引用改变被观察者;第二个问题信息太多,有的观察者只需要一部分信息即可,但是更新方法每次都会把固定的那些信息推过去,观察者们很无奈,只能照单收下,这种方法叫做推。
    b) 第二种方法是拉。很好理解,拉相比较推即是让观察者自己获取感兴趣的信息,在拉的观察者模式中,我们在更新方法中不传参数,而在被观察中编写所有要传递的信息的get方法,让观察者们自己获取想要获得的信息。
    c) 通常,我们采用推方法,推方法是主流方法。

  2. setChange方法
    a) 在JDK中有对观察者模式的实现,因为JDK中也有很多源代码是用观察者模式来实现的。在JDK的观察者模式中,我们发现多了一个setChange方法。这个方法的作用是设置一个字段change的布尔值,在更新方法中读取change的值判断是否需要进行更新。因为有的时候虽然数据发生了变化,但是我们不希望进行推送更新,那么这时我们将setChange方法设置为false即可避免更新观察者。

  3. JDK自带观察者模式缺点
    a) 继承问题。JDK自带的观察者模式是java.util.Observable类,这个类最大的问题在于是可以被继承的类而不是接口,这给我们的编程带来了很大的困扰,如果我们的类必须要继承另外一个类,那么意味着观察者模式必须要手动实现了。
    b) 时间问题。观察者模式需要被观察者主动的去更新观察者,如果观察者很多,那么通知的时间也很可观。而且这种通知,有时我们不敢使用多线程处理,因为要确保所有的观察者都获得了更新。
    c) 死锁问题。如果观察者与被观察者之间会发生循环调用则可能导致死锁问题,这种问题一般在于代码的编写问题,如果真的会发生类死锁问题,我们该考虑是不是真的应该使用观察者模式了。就算使用也要自己做额外的实现代码。
    d) 不存在内存问题。网上普遍说如果被观察者没有正确的被回收,那么观察者们可能得不到回收。这种说法是错的。Java虚拟机HotSpot采用可达性分析回收垃圾,不是引用计数法,不会发生内存泄露。

package ObserversEx;

import java.util.*;

public class Subject {

    private boolean changed;

    private ArrayList<Observer> observers = new ArrayList<Observer>();

    protected synchronized void setChange() {
        changed = true;
    }

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void changeObservers(String data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (changed) {
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }

    protected synchronized void clearChanged() {
        // TODO Auto-generated method stub
        changed = false;
    }

}
package ObserversEx;

public class Observer {

    public void update(Subject subject, String data) {
    }

}
package ObserversEx;

public class ObserverConcrete extends Observer {

    private String obserState;

    public void update(Subject subject, String data) {
        System.out.println("Message is " + data);
    }

}
package ObserversEx;

public class SubjectConcrete extends Subject {

    public synchronized void change(String state) {
        setChange();
        changeObservers(state);
    }

}
package ObserversEx;

public class Main {

    public static void main(String[] args) {

        SubjectConcrete subject = new SubjectConcrete();
        Observer observer = new ObserverConcrete();
        subject.addObserver(observer);
        subject.change("new state");

    }

}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值