Android 设计模式之观察者模式

参考:http://droidyue.com/blog/2015/06/27/desgign-pattern-observer/index.html

http://www.cnblogs.com/mythou/p/3370340.html


一.定义

观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。

1.关键要素

主题

主题是观察者观察的对象,一个主题必须具备下面三个特征。

持有监听的观察者的引用
支持增加和删除观察者
主题状态改变,通知观察者
观察者

当主题发生变化,收到通知进行具体的处理是观察者必须具备的特征。

2.为什么要用这种模式

这里举一个例子来说明,牛奶送奶站就是主题,订奶客户为监听者,客户从送奶站订阅牛奶后,会每天收到牛奶。如果客户不想订阅了,可以取消,以后就不会收到牛奶。

松耦合

观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。
主题只负责通知观察者,但无需了解观察者如何处理通知。举个例子,送奶站只负责送递牛奶,不关心客户是喝掉还是洗脸。
观察者只需等待主题通知,无需观察主题相关的细节。还是那个例子,客户只需关心送奶站送到牛奶,不关心牛奶由哪个快递人员,使用何种交通工具送达。
通知不错过

由于被动接受,正常情况下不会错过主题的改变通知。而主动获取的话,由于时机选取问题,可能导致错过某些状态。

3.简单实现

在java中,提供了一快速实现观察者设计模式的方案。
java中提供了一个类Observable和一个接口Observer

Observer这个接口的源码是这样的:

public interface Observer {

    /**
     * This method is called if the specified {@code Observable} object's
     * {@code notifyObservers} method is called (because the {@code Observable}
     * object has been updated.
     *
     * @param observable
     *            the {@link Observable} object.
     * @param data
     *            the data passed to {@link Observable#notifyObservers(Object)}.
     */
    void update(Observable observable, Object data);
}

其中Obervable有以下的方法

public class Observable {

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

    boolean changed = false;

    /**
     * Constructs a new {@code Observable} object.
     */
    public Observable() {
    }

    /**
     * Adds the specified observer to the list of observers. If it is already
     * registered, it is not added a second time.
     *
     * @param observer
     *            the Observer to add.
     */
    public void addObserver(Observer observer) {
        if (observer == null) {
            throw new NullPointerException("observer == null");
        }
        synchronized (this) {
            if (!observers.contains(observer))
                observers.add(observer);
        }
    }

    /**
     * Clears the changed flag for this {@code Observable}. After calling
     * {@code clearChanged()}, {@code hasChanged()} will return {@code false}.
     */
    protected void clearChanged() {
        changed = false;
    }

    /**
     * Returns the number of observers registered to this {@code Observable}.
     *
     * @return the number of observers.
     */
    public int countObservers() {
        return observers.size();
    }

    /**
     * Removes the specified observer from the list of observers. Passing null
     * won't do anything.
     *
     * @param observer
     *            the observer to remove.
     */
    public synchronized void deleteObserver(Observer observer) {
        observers.remove(observer);
    }

    /**
     * Removes all observers from the list of observers.
     */
    public synchronized void deleteObservers() {
        observers.clear();
    }

    /**
     * Returns the changed flag for this {@code Observable}.
     *
     * @return {@code true} when the changed flag for this {@code Observable} is
     *         set, {@code false} otherwise.
     */
    public boolean hasChanged() {
        return changed;
    }

    /**
     * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
     * method for every observer in the list of observers using null as the
     * argument. Afterwards, calls {@code clearChanged()}.
     * <p>
     * Equivalent to calling {@code notifyObservers(null)}.
     */
    public void notifyObservers() {
        notifyObservers(null);
    }

    /**
     * If {@code hasChanged()} returns {@code true}, calls the {@code update()}
     * method for every Observer in the list of observers using the specified
     * argument. Afterwards calls {@code clearChanged()}.
     *
     * @param data
     *            the argument passed to {@code update()}.
     */
    @SuppressWarnings("unchecked")
    public void notifyObservers(Object data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (hasChanged()) {
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }

    /**
     * Sets the changed flag for this {@code Observable}. After calling
     * {@code setChanged()}, {@code hasChanged()} will return {@code true}.
     */
    protected void setChanged() {
        changed = true;
    }
}
举个例子: 老师宣布现在到点了,可以去吃饭了,然后同学们收到这个消息后都下课吃饭去了

明显老师的观察对象,儿们是观察者

老师类

public class Teacher extends Observable {

    public  void sayMessage(String str){
        setChanged();  //必不可少的方法
        notifyObservers(str);


    }
}
学生类 学生1

public class Student1 implements Observer {
    @Override
    public void update(Observable observable, Object data) {
        Teacher teacher = (Teacher) observable;
        String something = (String) data;
        Log.e("Student1",observable+":"+something);
    }
}
学生2


public class Student2 implements Observer {
    @Override
    public void update(Observable observable, Object data) {
        Teacher teacher = (Teacher) observable;
        String something = (String) data;
        Log.e("Student2",teacher+":"+something);
    }
}

主函数里的写法:

Teacher teacher = new Teacher();
Student1 student1 = new Student1();
Student2 student2 = new Student2();
teacher.addObserver(student1);
teacher.addObserver(student2);

teacher.sayMessage("到点了,可以吃饭了");
运行结果:

E/Student1: ObverserPatterm.Teacher@39d87068说:到点了,可以吃饭了
E/Student2: ObverserPatterm.Teacher@39d87068说:到点了,可以吃饭了

在java里面可以使用这种现成方式去实现观察者模式,但是这个方法放在android上有缺陷。因为java里面是单继承多实现,android里面组件需要继承父类组件,比如一般的控件都要继承view、viewGroup本身或者子类,如果Teacher继承了Observable 那么他将不能再继承其他类了,那这个类功能就太单一了。

这个时候我们要需要自定义观察者设计模式

我们模仿类Observable,给发布者添加上面三种方法
public class Teacher {

    //1.定义接口,接口方法

    public interface MessageObserver{

        public void onMessageChanged(String message);
    }

    //2.定义集合放置我们的接口对象
    private List<MessageObserver> messageObservers = new ArrayList<MessageObserver>();

    //我们模仿类Observable,给发布者添加上面三种方法,代码改成
    //添加观察者
    public void addObserver(MessageObserver mObserver){
        if (mObserver ==null){
            throw new NullPointerException("mObserver ==null");
        }
        synchronized (this){
            if (!messageObservers.contains(mObserver)){
                messageObservers.add(mObserver);
            }
        }

    }
    //删除观察者
    public void deleteObserver(MessageObserver mObserver){
            messageObservers.remove(mObserver);
    }

    //数据更新
    public void noticeMessage(String message){
        for (MessageObserver o:messageObservers){
            o.onMessageChanged(message);
        }

    }

}
学生接口类的实现

public class Student1 implements Teacher.MessageObserver{


    @Override
    public void onMessageChanged(String message) {
        Log.e("student1","获取到的消息:"+message);
    }
}
测试方法

Teacher teacher = new Teacher();
Student1 student1 = new Student1();
Student2 student2 = new Student2();
teacher.addObserver(student1);
teacher.addObserver(student2);

teacher.noticeMessage("到点了12点了,可以吃饭了");

4、Android 应用开发中的观察者模式

  在我们做Android应用的时候,会大量使用观察者模式,因为Framework层里面的事件驱动都是基于观察者模式实现的。另外在Framework层里面的各种服务在数据变更的时候,也是通过观察者模式实现上层数据更新。下面会讲两个例子来说明:

1.控件中Listener监听方式

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        finish();
    }
});
例如上面的代码,注册了一个按钮的监听方法。这里实际上是应用了一对一的观察者模式,setOnClickListener()方法就是注册一个观察者,Button对象就是我们要观察的目标对象。而new出来的OnClickListener(),就是我们实际的观察者。
    每当我们的目标按钮对象被点击,状态发生变化的时候,就会通过回调注册的OnClickListener观察者的onClick方法会来通知观察者,Button状态发生变化。这里的onClick相当于前面例子里面的update方法。

public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    void onClick(View v);
}
参考自:http://blog.qiji.tech/archives/2966



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值