观察者模式的Java实现及应用

更新时间:2017-10-24 09:22:56 点击次数:1509次

观察者模式定义

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 
图片描述
关键字

Observable 
即被观察者,也可以被叫做主题(Subject)是被观察的对象。通常有注册方法(register),取消注册方法(remove)和通知方法(notify)。 
Observer 
即观察者,可以接收到主题的更新。当对某个主题感兴趣的时候需要注册自己,在不需要接收更新时进行注销操作。 
例子与应用

举一个生活中的例子:比如用户从报社订阅报纸,报社和用户之间是一对多依赖,用户可以在报社订阅(register)报纸,报社可以把新的报纸发给用户(notify),用户自动收到更新。在用户不需要的时候还可以取消注册(remove)。

再比如Android中的EventBus,Rxjava的实现都是基于观察者模式的思想。再比如回调函数:Android中对Button的点击监听等等。

观察者模式可以用来解耦

自己用代码实现一个观察者模式

现在我们用代码来实现上面订阅报纸的例子: 
NewProvider作为对于报社的抽象,每隔两秒钟向用户发送报纸;User作为用户的抽象,可以收到报纸。NewsModel作为对报纸本身的抽象。

/** 
* 被观察者接口定义 
*/ 
public interface MyObserverable {

void register(MyObserver myObserver);

void remove(MyObserver myObserver);

void send(NewsModel model); 


/** 
* 观察者接口定义 
*/ 
public interface MyObserver {

void receive(NewsModel model); 


/** 
* 对于报社的抽象,实现了被观察者接口,每隔2s发送一次报纸 
*/ 
public class NewsProvider implements MyObserverable { 
private static final long DELAY = 2 * 1000; 
private List mObservers; //我们用一个List来维护所有的观察者对象

public NewsProvider() {
    mObservers = new ArrayList<>();
    generateNews();
}

/**
 * 模拟产生新闻,每个2s发送一次
 */
private void generateNews() {
    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        int titleCount = 1;
        int contentCount = 1;

        @Override
        public void run() {
            send(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
        }
    }, DELAY, 1000);
}

@Override
public void register(MyObserver myObserver) {
    if (myObserver == null)
        return;
    synchronized (this) {
        if (!mObservers.contains(myObserver))
            mObservers.add(myObserver);
    }
}

@Override
public synchronized void remove(MyObserver myObserver) {
    mObservers.remove(myObserver);
}

@Override
public void send(NewsModel model) {
    for (MyObserver observer : mObservers) {
        observer.receiveNews(model);
    }
} 


/** 
* 对于用户的抽象 
*/ 
public class User implements MyObserver { 
private String mName;

public User(String name) {
    mName = name;
}

@Override
public void receive(NewsModel model) {
    System.out.println(mName + " receive news:" + model.getTitle() + "  " + model.getContent());
} 


/** 
* 测试类 
*/ 
public class Test { 
public static void main(String[] args) {

 NewsProvider provider = new NewsProvider();
    User user;
    for (int i = 0; i < 10; i++) {
        user = new User("user:"+i);
        provider.register(user);
    }

} 


运行结果如下: 
图片描述
这样我们就自己动手完成了一个简单的观察者模式。

其实在JDK的util包内Java为我们提供了一套观察者模式的实现,在使用的时候我们只需要继承Observable和Observer类即可,其实观察者模式十分简单,推荐阅读JDK的实现代码真心没有几行。此外在JDK的实现中还增加了一个布尔类型的changed域,通过设置这个变量来确定是否通知观察者。

下面我们用JDK的类来实现一遍我们的观察者模式:

public class NewsProvider extends Observable { 
private static final long DELAY = 2 * 1000;

public NewsProvider() {
    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
       private int titleCount = 1;
       private int contentCount = 1;
        @Override
        public void run() {
            setChanged(); //调用setChagned方法,将changed域设置为true,这样才能通知到观察者们
            notifyObservers(new NewsModel("title:" + titleCount++, "content:" + contentCount++));
        }
    }, DELAY, 1000);
} 


public class User implements Observer { 
private String mName;

public User(String name) {
    mName = name;
}

@Override
public void update(Observable observable, Object data) {
    NewsModel model = (NewsModel) data;
    System.out.println(mName + " receive news:" + model.getTitle() + "  " + model.getContent());
} 


非常简单有木有

回调函数与观察者模式

关于回调函数的定义在知乎上看到过一个很赞的解释:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。 
在Android中我们有一个常用的回调:对与View点击事件的监听。现在我们就来分析一下对于View的监听。 
通常在我们使用的时候是这样的:

 xxxView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // do something
        }
    }); 

这样我们就注册好了一个回调函数。 
我们可以在View的源码里发现这个接口:

/**
 * Interface definition for a callback to be invoked when a view is clicked.
 */
public interface OnClickListener {
    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    void onClick(View v);
} 

当你setClickListener的时候在View的源码中可以看到对本地OnClickListener的初始化

/**
 * Register a callback to be invoked when this view is clicked. If this view is not
 * clickable, it becomes clickable.
 *
 * @param l The callback that will run
 *
 * @see #setClickable(boolean)
 */
public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
    }
    getListenerInfo().mOnClickListener = l;
} 

当你的点击到一个View后Android系统经过一系列的调用后到了View的performClick方法中:

/** 
* Call this view’s OnClickListener, if it is defined. Performs all normal 
* actions associated with clicking: reporting accessibility event, playing 
* a sound, etc. 

* @return True there was an assigned OnClickListener that was called, false 
* otherwise is returned. 
*/ 
public boolean performClick() { 
final boolean result; 
final ListenerInfo li = mListenerInfo; 
if (li != null && li.mOnClickListener != null) { 
playSoundEffect(SoundEffectConstants.CLICK); 
li.mOnClickListener.onClick(this); 
result = true; 
} else { 
result = false; 
}

 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
    return result;
} 

就在这里,触发了你的onClick方法,然后执行方法体。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!