观察者模式的使用及分析

1.观察者模式介绍

image

  • Subject : 抽象被观察者(Observeable),吧所有观察者对象的医用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象被观察者提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject: 具体的被观察者,将有关状态存入具体的观察者对象,在具体的被观察者内部状态发生变化时,给所有注册的观察者发送通知。
  • Observer : 抽象观察者,定义了一个更新接口,使得在得到被观察者的通知时更新自己。
  • ConcreteObserver : 具体的观察者,实现了抽象观察者锁定义的接口,用来在收到通知时更新自己。

(注:继承是实线空心三角箭头,实现是虚线空心三角箭头)

2.Demo

自己写了一个javaDemo,在demo文件夹里

public class myClass {
    public static void main(String[] args) {
        System.out.print("hello world!");
        final TestObserverable testObserverable = new TestObserverable();

        final TestObserver testObserverOne = new TestObserver("TestObserver1");
        final TestObserver testObserverTwo = new TestObserver("TestObserver2");
        final TestObserver testObserverThree = new TestObserver("TestObserver3");
        //添加观察者到被观察者,等待被观察者有数据变化时去更新所有添加进来的观察者
        testObserverable.addObserver(testObserverOne);
        testObserverable.addObserver(testObserverTwo);
        testObserverable.addObserver(testObserverThree);

        ShowChange showChange = new ShowChange();

        testObserverOne.setOnDataChangedListener(showChange);
        testObserverTwo.setOnDataChangedListener(showChange);
        testObserverThree.setOnDataChangedListener(showChange);

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
    //                testObserverable.setChanged();
    //                testObserverable.notifyObservers();
                    Scanner scanner = new Scanner(System.in);
                    String inputString = scanner.next();
    //                testObserverable.notifyObservers(inputString);
                    testObserverable.notifyObserversDataChange(inputString);
                }
            });
            try {
                Thread.sleep(3000);
                thread.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    public static class ShowChange implements TestObserver.onDataChangedListener{
        @Override
        public void onDadaChange(String name) {
    //            System.out.print("观察者收到了被观察者的回调!!!!!!!!!!!");
                System.out.print("\n" + name + "has reseive TestObserverable notify,no parames");
            }

        @Override
        public void onDadaChange(String name, String result) {
            System.out.print("\n" + name + " has reseive TestObserverable notify, result : " + result);
        }
    }

}

上面是程序入口类,main方法

//具体观察者(TestObserver),实现抽象观察者Observer()
public class TestObserver implements Observer {
    private onDataChangedListener mDataChangedListener;
    private String mObserverName;
    public TestObserver(String name) {
        mObserverName = name;
    }

    @Override
    public void update(Observable observable, Object o) {
        String result = String.valueOf(o);
//        System.out.println(mObserverName + " receive TestObserverable notify");
        if (result == null || result == "") {
            mDataChangedListener.onDadaChange(mObserverName);
        } else {
            mDataChangedListener.onDadaChange(mObserverName, result);
        }
    }

    public void setOnDataChangedListener(myClass.ShowChange listener) {
        mDataChangedListener = listener;

    }

    public interface onDataChangedListener {
        public void onDadaChange(String name);
        public void onDadaChange(String name, String result);
    }

}

上面TestObserver是观察者类

//具体被观察者(TestObserverable),继承于抽象被观察者(Observable)
public class TestObserverable extends Observable{
    @Override
    protected synchronized void setChanged() {
        super.setChanged();
    }

    @Override
    public void notifyObservers() {
        super.notifyObservers();
    }

    @Override
    public void notifyObservers(Object o) {
        super.notifyObservers(o);
    }

    public void notifyObserversDataChange(String content) {
        setChanged();
        notifyObservers(content);
    }
    /**
     * 将观察者添加到被观察者中,当被观察者有变化时通知观察者
     * @param observer
     */
    @Override
    public synchronized void addObserver(Observer observer) {
        super.addObserver(observer);
    }
}

上面TestObserverable是被观察者类

  1. MyClass类里面的main方法中实例化多个TestObserver(观察者),并添加到TestObeserverable(被观察者)里面去,

  2. 然后调用TestObeserverable的notifyObserversDataChange(content)方法,TestObeserverable会先置changed状态值置为true,然后遍历已注册的观察者并通知观察者(观察者被回调update方法),打出相应的log。

  3. 输入要输入的内容看结果,如下

    hello world!
     I,amGaryCong
     
     TestObserver3 has reseive TestObserverable notify, result : I,amGaryCong
     TestObserver2 has reseive TestObserverable notify, result : I,amGaryCong
     TestObserver1 has reseive TestObserverable notify, result : I,amGaryCong

3.源码分析

结合上文例子分析 java.util 包下的 Observer 和 Observable 的实现。

接口 Observer

public interface Observer {
    void update(Observable o, Object arg);
}

很简单的一个接口,只定义了一个 update() 方法,参数 Observable 和 Object。 Observable o 表示具体的被观察者对象,Object arg 是要传递和更新的数据。

上文 MyTextView 实现该接口,并实现 update() 方法。该方法的作用是当 DataSource 发生数据变化时,会遍历所有已添加的 MyTextView 并调用它们的 update() 方法来更新 UI。

类 Observable

public class Observable { // 1.1 数据是否变化标记 private boolean changed = false; // 1.2 长度自增长数组 private Vector<Observer> obs;

/** Construct an Observable with zero Observers. */

public Observable() {
    obs = new Vector<>();
}
// 2.1 添加观察者对象
public synchronized void addObserver(Observer o) {
    if (o == null)
        throw new NullPointerException();
    if (!obs.contains(o)) {
        obs.addElement(o);
    }
}
// 2.2 删除观察者对象
public synchronized void deleteObserver(Observer o) {
    obs.removeElement(o);
}
// 3.1 通知所有观察者
public void notifyObservers() { 
    notifyObservers(null);
}

public void notifyObservers(Object arg) {
    Object[] arrLocal;
    // 线程同步
    synchronized (this) {
        // 3.2 获取是否发生变化的标记
        if (!hasChanged())
            return;
        // 3.3 转化为 Object 数组
        arrLocal = obs.toArray();
        // 重置标记
        clearChanged();
    }
    // 遍历所有观察者并调用其 update 方法
    for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
}
// 删除所有观察者对象
public synchronized void deleteObservers() {
    obs.removeAllElements();
}
// 设置标记为 true,表明数据发生了变化且已经通知过
protected synchronized void setChanged() {
    changed = true;
}
// 清除标记,恢复默认状态
protected synchronized void clearChanged() {
    changed = false;
}
// 获取标记
public synchronized boolean hasChanged() {
    return changed;
}
// 获取观察者的数量
public synchronized int countObservers() {
    return obs.size();
}
}

该类比较简单,按注释顺序来看:

  • 两个变量 changed 和 obs。changed是数据是否变化的标记,主要作用是避免重复通知观察者。obs是一个自增长的数组,用来存放具体的观察者对象,也就是实现了 Observer 的实现类。

  • 这里有一个知识点:设计模式的 依赖倒置原则:面向接口编程而不是面向具体对象编程。这个 obs 数组存放的是接口类型而不是某个具体实现类型表明了这一点。

  • 添加和删除观察者对象的方法就是往数组 obs 添加和删除元素。

  • notifyObservers() 通知所有观察者,可以看到该函数使用了 synchronized 保证线程安全,然后 hasChanged() 获取当前标记状态,如果标记为 false 则 return 不进行通知。

  • 那么这个标记什么时候才能为 true 呢?是在该类的子类中,也就是刚才例子中 DataSource 数据源类 updateData() 方法中首先调用 setChanged() 来设置标记为 true,表明数据即将进行更新。

  • 之后将数组 obs 转化为 Object 数组,设置标记为 false,然后遍历 obs 数组并调用所有元素的 update() 方法。也就是例子中所有添加进来的 MyTextView 对象的 update() 方法都会被调用,所有 MyTextView 的 text 发生变化。

  • 到这里 Observer(抽象观察者) 和 Observable(抽象被观察者)已经分析的差不多了,那么再结合刚才的例子来总结一下:

  • TestObserver 实现 Observer,是具体的观察者。实现方法 update() 来执行具体的逻辑。

  • TestObserverable 继承 Observable,是具体的被观察者。通过 notifyObservers() 方法传递具体数据来实现通知所有观察者,传递的具体逻辑是在父类中实现的。

  • Observable 作为抽象被观察者实现具体的数据传递逻辑,其内部维护了一个标记和具体观察者列表,当数据发生变化时遍历该列表并通过调用 update() 方法来通知具体观察者实现不同的逻辑。

4.在Android中的使用

最典型的就是ListView和Recyclerview的adapter.notifyDataSetChanged() 不浪费篇幅了

https://blog.csdn.net/qq_25806863/article/details/69218968

https://blog.csdn.net/u012124438/article/details/55294914/

都讲解了ListView的Adapter的观察者模式的使用原理。

5.广播就是典型的观察者模式

6.总结

优点

解除了观察者和被观察者的耦合,而且依赖的都是抽象,容易应对业务变化,各自的变化都不会影响另一个。
增强系统灵活性、可拓展性。

缺点

Java中的消息默认是顺序执行,如果一个观察者卡顿,会造成整个系统效率变低,可以考虑异步。
可能会引起无用的操作甚至错误的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值