设计模式--观察者模式

1、观察者模式

观察者模式又被称为发布订阅模式。它定义了对象之间一对多的依赖,当一个对象状态发生改变时,它的所有依赖者都会收到通知并自动更新相关内容。

观察者模式主要有两个角色

  • Subject 观察主题对象,也可以叫被观察或者被订阅对象。
  • Observer 观察者或者订阅者对象,当Subject有变动,就会通知到每一个Observer。

我们按照定牛奶的方式来理解,Subject实际上可以理解成奶厂,Observer可以理解成为我们每个用户,而观察者模式就是在Subject发生变化的时候,去通知每一个Observer对象,以达到消息通知目的。

在这里插入图片描述

2、自己实现一个观察者模式

定义观察者主题对象

/**
 * 观察者主题对象(被观察者)
 */
public interface Subject {

    /**
     * 订阅操作
     */
    void attach(Observer observer);

    /**
     * 取消订阅操作
     */
    void detach(Observer observer);

    /**
     * 通知变动
     */
    void notifyChanged();
}

定义观察者观察人对象

/**
  * 观察者订阅人对象
  */
 public interface Observer {

     /**
      * 接收变动通知
      */
     void update();
 }

 分别创建Subject和Observer对象的实现类

public class RealSubject implements Subject {
    private List<Observer> observerList = new ArrayList<>();

    @Override
    public void attach(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyChanged() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}
public class RealObject1 implements Observer {
    @Override
    public void update() {
        System.out.println("RealObject1 接收到了通知");
    }
}
public class RealObject2 implements Observer {
    @Override
    public void update() {
        System.out.println("RealObject2 接收到了通知");
    }
}

 Observer的实现可以是很多个,可以理解为平时一家奶厂,订奶用户肯定是有很多个。
调用实现

public class Test {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        Observer observer = new RealObject();
        subject.attach(observer);
        subject.notifyChanged();
    }
}

3、使用Java自带的观察者模式类实现

Java中提供了 java.util.Observable 和 java.util.Observer 来实现观察者模式。
上面自己通过接口的方式,实现了一个观察者模式,但是Java自身也是有这方面的实现了,下面看看如何用Java自带的实现一个观察者模式

public class RealSubject extends Observable {

    public void makeChanged() {
        setChanged();
        notifyObservers();
    }
}
public class RealObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("调用了-->");
    }
}
public class test {
    public static void main(String[] args) {
        RealSubject subject = new RealSubject();
        RealObserver observer = new RealObserver();
        subject.addObserver(observer);
        subject.makeChanged();
    }
}

调用的基本逻辑是一样的。Java已经帮我们把订阅和取消订阅操作都封装了起来,通知也进行了封装,并且进行了同步处理。只要需要注意的是,这里有个setChanged();,在发生变化之后,必须调用这个方法告诉发生了改变,否则不会正常处理消息的。

public void notifyObservers(Object arg) {
   /*
     * a temporary array buffer, used as a snapshot of the state of
     * current Observers.
     */
    Object[] arrLocal;

    synchronized (this) {
        /* We don't want the Observer doing callbacks into
         * arbitrary code while holding its own Monitor.
         * The code where we extract each Observable from
         * the Vector and store the state of the Observer
         * needs synchronization, but notifying observers
         * does not (should not).  The worst result of any
         * potential race-condition here is that:
         * 1) a newly-added Observer will miss a
         *   notification in progress
         * 2) a recently unregistered Observer will be
         *   wrongly notified when it doesn't care
         */
        if (!changed)   //这里的标志位就是setChanged处理的标志位
            return;
        arrLocal = obs.toArray();
        clearChanged();
    }

    for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
}


4、观察者模式的优缺点

优点

  • 解耦,被观察者只知道观察者列表「抽象接口」,被观察者不知道具体的观察者。
  • 被观察者发送通知,所有注册的观察者都会收到信息「可以实现广播机制」。


缺点

  • 如果观察者非常多的话,那么所有的观察者收到被观察者发送的通知会耗时。
  • 观察者知道被观察者发送通知了,但是观察者不知道所观察的对象具体是如何发生变化的。
  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃。
     

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值