前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java设计模式 | 观察者模式解析与实战

Java设计模式 | 观察者模式解析与实战

作者头像
凌川江雪
发布2020-04-14 17:19:23
8610
发布2020-04-14 17:19:23
举报
文章被收录于专栏:李蔚蓬的专栏李蔚蓬的专栏

概述

  • 观察者模式是一个**使用率**非常高的模式, 它最常用的地方是 GUI 系统、订阅——发布系统。
  • 这个模式的一个重要作用就是**解耦**, 将**被观察者**和**观察者**解耦, 使得它们之间的依赖性更小,甚至做到毫无依赖。
  • 以GUI系统来说,应用的UI具有易变性, 尤其是前期随着业务的改变或者产品的需求修改, 应用界面**也会**经常性变化**,但是**业务逻辑**基本变化不大,** 此时,GUI系统需要一套机制来应对这种情况, 使得**UI层**与**具体的业务逻辑**解耦,观察者模式此时就派上用场了。

!!! 因为**观察者**仅负责调度**被观察者**的**更新方法**, 并提供一个业务数据给**被观察者**; 被观察者**具体实现**更新方法**【可以实现UI、数据更新】,** 其**更新方法**具体实现的**内容**与**观察者**的**业务逻辑**基本毫无依赖!

定义

定义对象间一种**一对多**的**依赖关系**,

使得每当**一个对象**改变状态,

则所有**依赖于它的对象**都会得到**通知**并被**自动更新**。

使用场景

●关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系;

●事件多级触发场景;

●跨系统的消息交换场景,如**消息队列**、**事件总线**的**处理机制**。

UML类图

●Subject:抽象主题,也就是被观察(Observable)的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。

●ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体被观察者(Concrete Observable)角色。

●Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己。

观察者模式实现思路总结

观察者接口准备更新(数据或UI的)方法; 被观察者接口准备三个抽象方法; 观察者实现类具体实现更新逻辑,可以有参数,参数为更新需要的数据; 被观察者实现类准备一个观察者List以及实现三个方法: 1.观察者注册方法: 参数为某观察者,功能是把观察者参数加到观察者List中; 2.注销观察者方法: 参数为某观察者,功能是把观察者参数从观察者List中移除; 3.通知观察者方法:无参数或者把需要通知的数据作为参数, 功能是遍历所有已注册的观察者, 即遍历 注册添加到 观察者List中的观察者,逐个调用List中所有观察者的更新方法;即一次性更新所有已注册的观察者! 使用时, 实例化一个被观察者和若干个观察者, 将所有观察者注册到被观察者处, 调用被观察者的通知方法,一次性更新所有已注册的观察者!

案例

来自 Android | TCP的C(Java|Android)/S(Java)通信实战经典聊天室案例(文末附本案例代码实现概述、观察者模式实现小结)

  • 准备一个消息队列, 每一个Client发送过来的消息, 都会被加入到队列当中去, 队列中默认有一个子线程, 专门从队列中,死循环,不断去取数据(取出队列的队头), 取到数据就做相关处理,比如分发给其他的socket;
代码语言:javascript
复制
/**
 * <pre>
 *     desc   :每一个Client发送过来的消息,
 *             都会被加入到队列当中去,
 *             队列中默认有一个子线程,
 *             专门从队列中,死循环,不断去取数据,
 *             取到数据就做相关处理,比如分发给其他的socket;
 * </pre>
 */
public class MsgPool {

    private static MsgPool mInstance = new MsgPool();

    /*
        这里默认消息是String类型,
        或者可以自行封装一个Model 类,存储更详细的信息

        block n.块; 街区;障碍物,阻碍
        顾名思义,这是一个阻塞的队列,当有消息过来时,就把消息发送给这个队列,
        这边会起一个线程专门从队列里面去取消息,
        如果队列中没有消息,就会阻塞在原地
     */
    private LinkedBlockingQueue<String> mQueue = new LinkedBlockingQueue<>();

    public static MsgPool getInstance() {
        return mInstance;
    }

    private MsgPool() {
    }

    //这是一个阻塞的队列,
    // 当有消息过来时,即客户端接收到消息时,
    // 就把消息发送(添加)到这个队列中
    //现在所有的客户端都可以发送消息到这个队列中
    public void sendMsg(String msg) {
        try {
            mQueue.put(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    //要一早就调用本方法,
    // 启动这个读取消息的线程,在后台不断运行
    public void start() {
        //开启一个线程去读队列的数据
        new Thread() {
            @Override
            public void run() {
                //无限循环读取信息
                while (true) {
                    try {
                        //取出并移除队头;没有消息时,take()是阻塞的
                        String msg = mQueue.take();
                        notifyMsgComing(msg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    //被观察者方法,遍历所有已注册的观察者,一次性通知更新
    private void notifyMsgComing(String msg) {
        for (MsgComingListener listener : mListeners) {
            listener.onMsgComing(msg);
        }
    }

    //观察者接口
    public interface MsgComingListener {
        void onMsgComing(String msg);//更新方法
    }

    //被观察者,存放观察者
    private List<MsgComingListener> mListeners = new ArrayList<>();

    //被观察者方法,添加观察者到列表
    public void addMsgComingListener(MsgComingListener listener) {
        mListeners.add(listener);
    }
}

案例小结: 所有的客户端都可发送消息到队列中, 然后所有的客户端都在等待 消息队列的消息新增(mQueue.put())这个时刻, 消息队列一新增消息, 即一接收到某个客户端发送过来消息(mQueue.put()), 则消息都会一次性转发给所有客户端, 所以这里涉及到一个观察者设计模式, 消息队列(MsgPool)或消息(Msg)是被观察者, 所有客户端处理线程(ClientTask)都是观察者


参考:

  • 《Android源码设计模式解析与实战》
  • 慕课网
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 定义
  • 使用场景
  • UML类图
  • 观察者模式实现思路总结
  • 案例
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档