观察者模式--Java设计模式

2023-05-16

观察者模式定义:定义了对象之间的一对多的依赖,这样一来,当一个对象发生改变状态的时候,它的所有依赖者都会收到通知并自动更新。参考如下图:
观察者模式表达图

观察者设计模式也叫发布-订阅模式。
也可以称作:出版者+订阅者 = 观察者模式
在Android中观察者模式的实例有:广播机制,ContentObserver的注册方式,一个是同步的观察者模式,一个是异步的观察者模式。

当两个对象之间松耦合,它们依然可以交互,但是不清楚彼此的细节,观察者提供了一种对象的设计,可以降低之间的耦合,避免对象的双向依赖。
举例:在Android中很多的Listener是观察者模式,比如点击事件的OnClickListener,就是为了避免对象的双向依赖。

—-先来看看Java源码中的观察者模式:

Observer观察者接口:

package com.daming.java.observer;

public interface Observer {

    void update(Observable observable, Object arg);
}

对象Observable 类的实现

package com.daming.java.observer;

import java.util.Vector;

public class Observable {

    private boolean changed = false;
    private Vector obs;

    public Observable() {
        obs = new Vector();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

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

    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

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

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }

    /**
     * Returns the number of observers of this <tt>Observable</tt> object.
     * 
     * @return the number of observers of this object.
     */
    public synchronized int countObservers() {
        return obs.size();
    }

}

MyObserver 观察者对象的实现

package com.daming.java.observer;

public class MyObserver implements Observer{

    @Override
    public void update(Observable observable, Object arg) {
        System.out.println("observable :" + observable + "arg :" + arg);
    }
}

MyObserver2 观察者对象的实现

package com.daming.java.observer;

public class MyObserver2 implements Observer{

    @Override
    public void update(Observable observable, Object arg) {
        System.out.println("observable2 :" + observable + "arg2 :" + arg);
    }
}

TestObserver类的实现

package com.daming.java.observer;

public class TestObserver {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Observable observable = new Observable();
        MyObserver myObserver = new MyObserver();
        MyObserver2 myObserver2 = new MyObserver2();
        observable.addObserver(myObserver);
        observable.addObserver(myObserver2);

        observable.setChanged();
        observable.notifyObservers(14);

        observable.setChanged();
        observable.notifyObservers("I am daming");
    }
}

Log输入结果:

observable2 :com.daming.java.observer.Observable@14318bbarg2 :14
observable :com.daming.java.observer.Observable@14318bbarg :14
observable2 :com.daming.java.observer.Observable@14318bbarg2 :I am daming
observable :com.daming.java.observer.Observable@14318bbarg :I am daming

Java源码中上述代码中用的是推模式,当然源码中也有拉模式,即主动查询的模式。拉模式就像广播一样,通过onReceive()方法拉起来一些动作的,还有像ContentObserver可以通过拉模式,当数据库发生改变的时候,通过onChange()方法来调用一些操作。

—-接着我们来看看Android中异步的观察者模式。

ContentObserver就是异步的观察者模式,异步的观察者有什么好处呢?不阻塞观察者的回调。在同步通知中会有阻塞问题,各个Observer的响应方法是串行的,如果有一个observer耗时的话就会阻塞其他observer接收者了,这样就有可能就会引起bug来,所以在设计的时候多考虑一些,是否考虑用异步的观察者模式,让并发处理快一些;我们通过一个简单的demo来学习下异步的观察者模式:

先来看看Observer,这个Android中是抽象的类

package cn.daming.observer.design;

import android.os.Handler;
import android.util.Log;

public abstract class Observer {

    private Handler mHandler;

    public Observer(Handler handler) {
        mHandler = handler;
    }

    public void onChange() {
    }

    public final void dispatchChange() {
        Log.v("daming", "Observer dispatchChange is mHandler== null :" + (mHandler == null));
        if (mHandler == null) {
            onChange();
        } else {
            mHandler.post(new NotificationRunnable());
        }
    }

    private final class NotificationRunnable implements Runnable {

        @Override
        public void run() {
            Log.v("daming", "NotificationRunnable dispatchChange is run ... ");
            Observer.this.onChange();
        }
    }
}

接着来看看ObserverService这个类的实现:

package cn.daming.observer.design;

import java.util.ArrayList;
import java.util.List;

import android.util.Log;

public class ObserverService {

    private int mState;

    private List<Observer> mObservers = new ArrayList<Observer>();

    public final void registerObserver(Observer observer) {
        if (!mObservers.contains(observer)) {
            mObservers.add(observer);
        }
    }

    public final void unregisterObserver(Observer observer) {
        Log.v("daming", "ObserverService unregisterObserver :");
        mObservers.remove(observer);
    }

    public void notifyChange() {
        for (Observer observer : mObservers) {
            observer.dispatchChange();
        }
    }

    public int getState() {
        return mState;
    }

    public void setState(int state) {
        mState = state;
        notifyChange();
    }
}

最后我们来写测试类FirstActivity :

package cn.daming.observer.design;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.daming.designtraning.R;

public class FirstActivity extends Activity {

    private ObserverService mObserverService;
    private Button mButton;
    private int mState = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.button);

        mObserverService = new ObserverService();
        mObserverService.registerObserver(mFirstObserver);
        mObserverService.setState(++mState);


        mButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                mObserverService.setState(++mState);
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mObserverService.unregisterObserver(mFirstObserver);

    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    private Observer mFirstObserver = new Observer(new Handler()) {

        @Override
        public void onChange() {
            int state = mObserverService.getState();
            Log.v("daming", "FirstObserver onChange is run state :" + state);
        }

    };
}

总结:通过Handler来实现异步的观察者模式,即构造Observer对象的时候传一个Handler的对象,这样在回调的时候,就用handler来发送异步的消息在主线程上来执行相应的操作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

观察者模式--Java设计模式 的相关文章

  • 如何在Netbeans中插入main方法(快捷方式)

    有时您想运行单个文件来快速测试某些代码 正在输入public static void main String args 每次都很乏味 怎样才能做得更快呢 由于 Netbeans 中预定义的代码模板 这很简单 只需输入psvm并按 Tab 键
  • 具有默认值的 Java JAX-RS 自定义参数

    假设我有这个 这只是一个示例 GET Path value address Produces application json public Response getAddress QueryParam user User user 用户是
  • 我在socket上设置了超时,发现这个值不能大于21

    我在socket上设置了超时 该值小于21秒才有效 21秒后发现超时还是21秒 public static void main String args SimpleDateFormat sdf new SimpleDateFormat yy
  • Java - 如何将特殊字符放入字符串中

    Java 似乎有很好的字符串处理能力 尽管如此 我还是遇到了最简单的问题 我需要动态字符串 它们在运行时更改 因此字符串类型不是一个好的选择 因为它们是不可变的 所以我使用字符数组 设置起来有点痛苦 但至少它们是可以修改的 我想创建一个字符
  • 将 Hibernate 对象序列化为 JSON 时抛出异常

    好吧 我正在使用 Hibernate 将一个小型数据库加载到一些表示表的类并与数据库交互 一切都很好 我真的可以看到所有结果 而且我没有任何空字段 所有这些都已被使用 这里我展示了 主 类 表 import javax persistenc
  • Google App Engine with Java - 运行 javac.exe 编译器时出错

    在 Windows XP 上 刚刚下载并解压谷歌应用程序引擎java sdk to C Program Files appengine java sdk 我已经安装了jdk C Program Files Java jdk1 6 0 20
  • 防止 Spring Boot 注册 Spring Security 过滤器之一

    我想禁用安全链中的 Spring Security 过滤器之一 我已经看到了防止 Spring Boot 注册 servlet 过滤器 https stackoverflow com questions 28421966 prevent s
  • 使用 ChannelExec 的命令未执行 - Jsch

    我正在使用 Jsch 在服务器中创建一个文件并执行一些命令 对于文件创建 它工作正常 但是对于命令执行 则不然 它保持状态 1 仍在处理它 并永远保持该状态 这种情况发生在 shell 执行或我尝试成为 root 时 请按照以下方法操作 p
  • 请参阅 Java EE eclipse 调试中的 POST 参数

    我在调试 Java EE 方面没有经验 我更像是一个 javascript 人 我需要查看哪些 HTTP POST 参数到达服务器端 我在表单将其操作指向的 jsp 文件中放置了一个断点 现在我在调试变量窗口中找不到 POST 内容 他们在
  • 异步迭代器

    我有以下代码 while slowIterator hasNext performLengthTask slowIterator next 由于迭代器和任务都很慢 因此将它们放入单独的线程中是有意义的 这是对迭代器包装器的快速而肮脏的尝试
  • 当您在数组列表上调用remove(object o)时,它如何比较对象?

    当您在 java 中的数组列表上调用remove object o 时 它如何比较对象以找到要删除的正确对象 它使用指针吗 或者它使用 Comparable 接口来比较对象吗 ArrayList remove 依赖于对象的实现Equal方法
  • 在 Java 中将弯音发送到 MIDI 音序器

    我了解启动和运行 MIDI 音序器的基础知识 并且希望能够在播放过程中增加 减小序列的音高 但弯音是发送到合成器而不是音序器的消息 我尝试将音序器的接收器设置为合成器的发射器 当我发送弯音短消息时 音序器保持相同的音调 但随后合成器以新的弯
  • 如何找到被点击的JLabel并从中显示ImageIcon?

    这是我的代码 我想知道哪个l单击 然后在新框架中显示该 ImageIcon e getSource 不起作用 final JFrame shirts new JFrame T shirts JPanel panel new JPanel n
  • 创建正则表达式匹配数组

    在Java中 我试图将所有正则表达式匹配返回到一个数组 但似乎您只能检查模式是否匹配某些内容 布尔值 如何使用正则表达式匹配来形成与给定字符串中的正则表达式匹配的所有字符串的数组 4城堡的回答 https stackoverflow com
  • 如何将 arraylist 从 servlet 传递到 javascript?

    我通过在属性中设置数组列表并将其转发到 jsp 来从 servlet 传递数组列表 Servlet ArrayList
  • 改变for循环的顺序?

    我遇到一种情况 我需要根据用户输入以不同的顺序循环遍历 xyz 坐标 所以我是 3D 空间中的一个区域 然后是一组像这样的 for 循环 for int x 0 x lt build getWidth x for int y 0 y lt
  • JavaFX - 为什么多次将节点添加到窗格或不同的窗格会导致错误?

    我现在正在学习基本的 JavaFX 我不明白我正在阅读的书中的这一说法 不 诸如文本字段之类的节点只能添加到一个窗格中一次 将节点添加到多次窗格或不同的窗格将导致运行时错误 我可以从书中提供的UML图看出它是一个组合 但我不明白为什么 库类
  • 警告:无法更改每个人的权限:

    当运行 Java 快速入门示例时https developers google com drive web quickstart java hl hu https developers google com drive web quicks
  • 无法使用 wget 在 CentOS 机器上安装 oracle jdk

    我想在CentOS上安装oracle java jdk 8 我无法安装 java jdk 因为当我尝试使用命令安装 java jdk 时 root ADARSH PROD1 wget no cookies no check certific
  • Java、Spring、Hibernate找不到org.springframework.orm.hibernate3.LocalSessionFactoryBean

    我正在尝试制作 spring hibernate ant 项目 目前我收到此错误 HTTP Status 500 type Exception report message description The server encountere

随机推荐