美文网首页设计模式
设计模式实践-观察者模式

设计模式实践-观察者模式

作者: h2coder | 来源:发表于2020-10-16 00:29 被阅读0次

什么是观察者模式?什么时候用?

观察者模式常用于GUI。它适用于一对多事件触发的场景,当一个对象的状态被改变,所有依赖它的对象都会得到通知并更新。

场景

  • 一对多的事件更新,如控件的点击、长按事件,动画的执行监听等等。
  • 跨区域的消息交换,如广播、事件总线等。

怎么实现观察者模式?

经典观察者模式,一般会涉及以下几个对象:

  • Subject抽象主题,就是Observable被观察者,抽象为接口,提供增、删观察者
  • ConcreteSubject,具体主题,实现Subject接口,将观察者的引用保存到一个集合中,更新时遍历集合通知观察者。
  • Observer,抽象观察者,也是一个接口。将更新作为接口方法。
  • ConcreteObserver,具体的观察者,实现Observer接口,在更新方法回调时,更新自身。

而我们平时写的接口回调,一般是没有太多抽象接口的,只有以下几个对象:

  • Observer,事件回调接口。提供更新方法。

  • 具体事件发出者,被观察者。提供增、删观察者。

其实经典的观察者模式,在JDK中已经提供了Observable和Observer接口,我们直接使用即可。

观察者模式实践,解耦分发聊天室消息

在开发聊天室的过程中,使用WebSocket接收后端发送过来的消息,一般为Json结构,我们就需要解析,解析完成为Java Bean后,再使用Bean进行UI更新。如果直接将解析操作直接写在Activity肯定是很臃肿的(消息种类非常多,将近10种),势必需要抽象去别的类上。而聊天室是分免费和付费的,有一部分消息是他们公用的(一般抽取一个基类),而有一些是个别类型的聊天室才需要使用,那么为了将消息结果解析方消息结果使用方解耦开来,我们可以使用观察者模式。

实现步骤

  1. Parser,消息解析方,解析消息Json,并提供消息回调,内部存储回调对象的引用。
  2. OnReceiveMsgCallback,消息结果使用方,为一个接口,每个监听对象都需要实现。
  3. 具体的OnReceiveMsgCallback实现类,聊天室有2种类型,再加上公用消息基类监听,一共3个。

最后,OnReceiveMsgCallback接口,提供空实现的实现类,每种类型的聊天室,看业务需要复写具体需要处理的类型回调方法即可。

别废话,上代码~

  1. 消息注册,3个示例一下(其他类型都是一样套路),接收房间信息、限制发送消息、订单支付消息。一般后端给的Json中,每种消息类型都有一个type来区分消息类型,我们每个消息解析判断本地Json中的type是否是我们这个接收器能处理的类型后再解析即可,解析完成后进行接口回调给外部即可。

    • 房间消息,不管免费、付费聊天室都需要。
    • 限制发送消息,免费的才需要,5条消息后,老师未回复,则产生限制,无法再发送,除非老师进行回复后,方可解除限制。
    • 订单支付消息,付费聊天室使用,用户下单后发送。
public class ConsultingMsgParser {
    /**
     * 注册房间信息
     */
    private void registerRoomInfo(ObservableSubscribeProxy<WebSocketInfo> proxy) {
        proxy.subscribe(new WebSocketGenericObserver<WssResponseModel<RoomInfoModel>>() {

            @Override
            protected boolean isTargetType(String json) {
                    //判断是否能够解析
                return canHandleJson(json, WssCommandTypeEnum.ROOM_INFO);
            }

            @Override
            protected ObservableSource<WssResponseModel<RoomInfoModel>> onParseData(String json) {
                    //能够解析,则解析并返回解析结果
                return parseResponse(json, new TypeToken<WssResponseModel<RoomInfoModel>>() {
                }.getType());
            }

            @Override
            protected void onMessage(WssResponseModel<RoomInfoModel> response) {
                   //通知观察者们,将结果传入
                for (OnReceiveMsgCallback callback : mOnReceiveMsgCallbackList) {
                    callback.onReceiveRoomInfo(response);
                }
            }
        });
    }
    
    /**
     * 注册免费聊天消息限制消息
     */
    private void registerFreeMsgLimit(ObservableSubscribeProxy<WebSocketInfo> proxy) {
        proxy.subscribe(new WebSocketGenericObserver<WssResponseModel<SendMsgLimitModel>>() {
            @Override
            protected boolean isTargetType(String json) {
                return canHandleJson(json, WssCommandTypeEnum.SEND_MSG_LIMIT);
            }

            @Override
            protected ObservableSource<WssResponseModel<SendMsgLimitModel>> onParseData(String json) {
                return parseResponse(json, new TypeToken<WssResponseModel<SendMsgLimitModel>>() {
                }.getType());
            }

            @Override
            protected void onMessage(WssResponseModel<SendMsgLimitModel> response) {
                for (OnReceiveMsgCallback callback : mOnReceiveMsgCallbackList) {
                    if (callback != null) {
                        if (MsgLimitEnum.LIMIT.getCode() == response.getData().getIsLimit()) {
                            //限制
                            callback.onReceiveSendMsgLimitMsg(response);
                        } else if (MsgLimitEnum.REMOVE_LIMIT.getCode() == response.getData().getIsLimit()) {
                            //解除限制
                            callback.onReceiveSendMsgRemoveLimitMsg(response);
                        }
                    }
                }
            }
        });
    }
    
    /**
     * 注册支付高级服务订单消息
     */
    private void registerPayServerOrderMsg(ObservableSubscribeProxy<WebSocketInfo> proxy) {
        proxy.subscribe(new WebSocketGenericObserver<WssResponseModel<PayServerOrderMsgModel>>() {
            @Override
            protected boolean isTargetType(String json) {
                return isTargetMsg(json, MsgTypeEnum.PAY_SERVER);
            }

            @Override
            protected ObservableSource<WssResponseModel<PayServerOrderMsgModel>> onParseData(String json) {
                return parseResponse(json, new TypeToken<WssResponseModel<PayServerOrderMsgModel>>() {
                }.getType());
            }

            @Override
            protected void onMessage(WssResponseModel<PayServerOrderMsgModel> response) {
                for (OnReceiveMsgCallback callback : mOnReceiveMsgCallbackList) {
                    callback.onReceivePayServerOrderMsg(response);
                }
            }
        });
    }
}
  1. 回调接口,一系列消息的回调
public interface OnReceiveMsgCallback {
    /**
     * 接收到房间信息
     */
    void onReceiveRoomInfo(WssResponseModel<RoomInfoModel> response);

    /**
     * 限制发送消息
     */
    void onReceiveSendMsgLimitMsg(WssResponseModel<SendMsgLimitModel> response);

    /**
     * 解除限制,发送消息
     */
    void onReceiveSendMsgRemoveLimitMsg(WssResponseModel<SendMsgLimitModel> response);

    /**
     * 高级服务支付订单消息
     */
    void onReceivePayServerOrderMsg(WssResponseModel<PayServerOrderMsgModel> response);
}

//因为有些消息,某种类型的聊天室不需要使用,所以提供接口空实现,具体类型聊天室看业务需要,复写对应类型的回调方法进行处理即可。
public class SimpleOnReceiveMsgCallback implements OnReceiveMsgCallback {
    @Override
    public void onReceiveRoomInfo(WssResponseModel<RoomInfoModel> response) {
    }
    
    @Override
    public void onReceiveSendMsgLimitMsg(WssResponseModel<SendMsgLimitModel> response) {
    }

    @Override
    public void onReceiveSendMsgRemoveLimitMsg(WssResponseModel<SendMsgLimitModel> response) {
    }
    
    @Override
    public void onReceivePayServerOrderMsg(WssResponseModel<PayServerOrderMsgModel> response) {
    }
}
  1. 提供注册接口回调的方法
private ArrayList<OnReceiveMsgCallback> mOnReceiveMsgCallbackList;

/**
 * 注册消息接收的回调
 */
public void registerOnReceiveMsgCallback(OnReceiveMsgCallback onReceiveMsgCallback) {
    if (mOnReceiveMsgCallbackList == null) {
        mOnReceiveMsgCallbackList = new ArrayList<>();
    }
    mOnReceiveMsgCallbackList.add(onReceiveMsgCallback);
}
  1. 3个结果处理方进行注册。

    • 房间消息,在基类注册进行处理。
    ConsultingMsgParser msgParser = new ConsultingMsgParser();
    msgParser.registerOnReceiveMsgCallback(new SimpleOnReceiveMsgCallback() {
                @Override
                public void onReceiveRoomInfo(WssResponseModel<RoomInfoModel> response) {
                    //收到房间信息,将信息设置到UI...
                    //开始获取消息列表...
                    getMsgList();
                }
    }
    
    • 限制发送消息,免费聊天室进行注册。
    msgParser.registerOnReceiveMsgCallback(new SimpleOnReceiveMsgCallback() {
    @Override
            public void onReceiveSendMsgLimitMsg(WssResponseModel<SendMsgLimitModel> response) {
                super.onReceiveSendMsgLimitMsg(response);
                //设置为限制发送消息状态
                mBanTipContext.setState(new LimitSendMsgBanTipState(model));
            }
    
            @Override
            public void onReceiveSendMsgRemoveLimitMsg(WssResponseModel<SendMsgLimitModel> response) {
                super.onReceiveSendMsgRemoveLimitMsg(response);
                //解除限制发送消息,恢复到普通状态
                mBanTipContext.setState(new NormalBanTipState());
            }
    }
    
    • 用户下单消息,付费聊天室进行注册
        msgParser.registerOnReceiveMsgCallback(new SimpleOnReceiveMsgCallback() {
        @Override
            public void onReceivePayServerOrderMsg(WssResponseModel<PayServerOrderMsgModel> response) {
                   //接收下单成功的系统消息
                //插入时间戳条目
                insertTimestampItem(response.getDateTime());
                //插入系统提示条目
                addSystemMsg(new PayServerSuccessTipModel());
                //滚动到底部
                scrollToBottom();
            }
        }
    

总结

  • 观察者模式的优点:将被观察者和观察者完全隔离,是解耦的。

  • 观察者模式的缺点:因为遍历被观察者是同步执行的,如果其中一个观察者回调时处理非常耗时,则影响到下一个遍历的观察者。这种情况观察者接收到消息后应该异步执行,不阻塞消息处理。

相关文章

  • 观察者设计模式

    每周学点Java设计模式__观察者设计模式 本次继续更新java23中设计模式之一——观察者模式。 观察者模式(有...

  • 第十三章 RecyclerView解析

    详细请看设计模式与实践 观察者模式解析 一、RecyclerView是什么 RecyclerView 比 List...

  • RxJava基础—观察者模式

    设计模式-观察者模式 观察者模式:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式...

  • 设计模式02-观察者者设计模式

    [toc] 设计模式02-观察者者设计模式 主要来源Head First设计模式(书)观察者设计模式是JDK中使用...

  • 11.9设计模式-观察者模式-详解

    设计模式-观察者模式 观察者模式详解 观察者模式在android中的实际运用 1.观察者模式详解 2.观察者模式在...

  • RxJava设计模式与原理

    标准观察者设计模式 RxJava是一种特殊的观察者模式,首先我们先来看标准的观察者设计模式。在标准观察者模式中,存...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • Guava源码分析——EventBus

    EventBus的设计理念是基于观察者模式的,可以参考设计模式(1)—观察者模式先来了解该设计模式。 1、程序示例...

  • 设计模式之观察者模式

    设计模式之观察者模式 本篇是设计模式系列博客的第四篇,本篇主要学习设计模式中的第二个行为型模式---观察者模式。 ...

  • 设计模式整理(9) 观察者模式

    学习《Android 源码设计模式解析与实践》系列笔记 介绍 观察者模式是使用率非常高的模式,最常用在 GUI 系...

网友评论

    本文标题:设计模式实践-观察者模式

    本文链接:https://www.haomeiwen.com/subject/ofompktx.html