用Java设计模式中的观察者模式开发微信公众号的例子

还记得警匪片上,匪徒们是怎么配合实施犯罪的吗?一个团伙在进行盗窃的时候,总有一两个人在门口把风——如果有什么风吹草动,则会立即通知里面的同伙紧急撤退。也许放风的人并不一定认识里面的每一个同伙;而在里面也许有新来的小弟不认识这个放风的。但是这没什么,这个影响不了他们之间的通讯,因为他们之间有早已商定好的暗号。
呵呵,上面提到的放风者、偷窃者之间的关系就是观察者模式在现实中的活生生的例子。

观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式。GOF给观察者模式如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
在这里先讲一下面向对象设计的一个重要原则——单一职责原则。因此系统的每个对象应该将重点放在问题域中的离散抽象上。因此理想的情况下,一个对象只做一件事情。这样在开发中也就带来了诸多的好处:提供了重用性和维护性,也是进行重构的良好的基础。
因此几乎所有的设计模式都是基于这个基本的设计原则来的。观察者模式的起源我觉得应该是在GUI和业务数据的处理上,因为现在绝大多数讲解观察者模式的例子都是这一题材。但是观察者模式的应用决不仅限于此一方面。

好了,对于定义的理解总是需要实例来解析的,如今的微信服务号相当火啊,下面就以微信服务号为背景,给大家介绍观察者模式。
看一张图:

其中每个使用者都有上图中的3条线,为了使图片清晰省略了。
如上图所示,服务号就是我们的主题,使用者就是观察者。现在我们明确下功能:
1、服务号就是主题,业务就是推送消息
2、观察者只需要订阅主题,只要有新的消息就会送来
3、当不想要此主题消息时,取消订阅
4、只要服务号还在,就会一直有人订阅
好了,现在我们来看看观察者模式的类图:

接下来就是代码时间了,我们模拟一个微信3D彩票服务号,和一些订阅者。
首先开始写我们的主题接口,和观察者接口:

package com.zhy.pattern.observer; 

/**
 * 主题接口,所有的主题必须实现此接口
 *
 * @author zhy
 *
 */
public interface Subject
{
  /**
   * 注册一个观察着
   *
   * @param observer
   */
  public void registerObserver(Observer observer); 

  /**
   * 移除一个观察者
   *
   * @param observer
   */
  public void removeObserver(Observer observer); 

  /**
   * 通知所有的观察着
   */
  public void notifyObservers(); 

} 

package com.zhy.pattern.observer; 

/**
 * @author zhy 所有的观察者需要实现此接口
 */
public interface Observer
{
  public void update(String msg); 

}

接下来3D服务号的实现类:

package com.zhy.pattern.observer; 

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

public class ObjectFor3D implements Subject
{
  private List<Observer> observers = new ArrayList<Observer>();
  /**
   * 3D彩票的号码
   */
  private String msg; 

  @Override
  public void registerObserver(Observer observer)
  {
    observers.add(observer);
  } 

  @Override
  public void removeObserver(Observer observer)
  {
    int index = observers.indexOf(observer);
    if (index >= 0)
    {
      observers.remove(index);
    }
  } 

  @Override
  public void notifyObservers()
  {
    for (Observer observer : observers)
    {
      observer.update(msg);
    }
  } 

  /**
   * 主题更新消息
   *
   * @param msg
   */
  public void setMsg(String msg)
  {
    this.msg = msg; 

    notifyObservers();
  } 

}

模拟两个使用者:

package com.zhy.pattern.observer; 

public class Observer1 implements Observer
{ 

  private Subject subject; 

  public Observer1(Subject subject)
  {
    this.subject = subject;
    subject.registerObserver(this);
  } 

  @Override
  public void update(String msg)
  {
    System.out.println("observer1 得到 3D 号码 -->" + msg + ", 我要记下来。");
  } 

}
package com.zhy.pattern.observer; 

public class Observer2 implements Observer
{
  private Subject subject ;  

  public Observer2(Subject subject)
  {
    this.subject = subject ;
    subject.registerObserver(this);
  } 

  @Override
  public void update(String msg)
  {
    System.out.println("observer2 得到 3D 号码 -->" + msg + "我要告诉舍友们。");
  } 

}

可以看出:服务号中维护了所有向它订阅消息的使用者,当服务号有新消息时,通知所有的使用者。整个架构是一种松耦合,主题的实现不依赖与使用者,当增加新的使用者时,主题的代码不需要改变;使用者如何处理得到的数据与主题无关;
最后看下测试代码:

package com.zhy.pattern.observer.test; 

import com.zhy.pattern.observer.ObjectFor3D;
import com.zhy.pattern.observer.Observer;
import com.zhy.pattern.observer.Observer1;
import com.zhy.pattern.observer.Observer2;
import com.zhy.pattern.observer.Subject; 

public class Test
{
  public static void main(String[] args)
  {
    //模拟一个3D的服务号
    ObjectFor3D subjectFor3d = new ObjectFor3D();
    //客户1
    Observer observer1 = new Observer1(subjectFor3d);
    Observer observer2 = new Observer2(subjectFor3d); 

    subjectFor3d.setMsg("20140420的3D号码是:127" );
    subjectFor3d.setMsg("20140421的3D号码是:333" ); 

  }
}

输出结果:

observer1 得到 3D 号码 -->20140420的3D号码是:127, 我要记下来。
observer2 得到 3D 号码 -->20140420的3D号码是:127我要告诉舍友们。
observer1 得到 3D 号码 -->20140421的3D号码是:333, 我要记下来。
observer2 得到 3D 号码 -->20140421的3D号码是:333我要告诉舍友们。

对于JDK或者Andorid中都有很多地方实现了观察者模式,比如XXXView.addXXXListenter , 当然了 XXXView.setOnXXXListener不一定是观察者模式,因为观察者模式是一种一对多的关系,对于setXXXListener是1对1的关系,应该叫回调。

恭喜你学会了观察者模式,上面的观察者模式使我们从无到有的写出,当然了java中已经帮我们实现了观察者模式,借助于java.util.Observable和java.util.Observer。
下面我们使用Java内置的类实现观察者模式:

首先是一个3D彩票服务号主题:

package com.zhy.pattern.observer.java; 

import java.util.Observable; 

public class SubjectFor3d extends Observable
{
  private String msg ;  

  public String getMsg()
  {
    return msg;
  } 

  /**
   * 主题更新消息
   *
   * @param msg
   */
  public void setMsg(String msg)
  {
    this.msg = msg ;
    setChanged();
    notifyObservers();
  }
}

下面是一个双色球的服务号主题:

package com.zhy.pattern.observer.java; 

import java.util.Observable; 

public class SubjectForSSQ extends Observable
{
  private String msg ;  

  public String getMsg()
  {
    return msg;
  } 

  /**
   * 主题更新消息
   *
   * @param msg
   */
  public void setMsg(String msg)
  {
    this.msg = msg ;
    setChanged();
    notifyObservers();
  }
}

最后是我们的使用者:

package com.zhy.pattern.observer.java; 

import java.util.Observable;
import java.util.Observer; 

public class Observer1 implements Observer
{ 

  public void registerSubject(Observable observable)
  {
    observable.addObserver(this);
  } 

  @Override
  public void update(Observable o, Object arg)
  {
    if (o instanceof SubjectFor3d)
    {
      SubjectFor3d subjectFor3d = (SubjectFor3d) o;
      System.out.println("subjectFor3d's msg -- >" + subjectFor3d.getMsg());
    } 

    if (o instanceof SubjectForSSQ)
    {
      SubjectForSSQ subjectForSSQ = (SubjectForSSQ) o;
      System.out.println("subjectForSSQ's msg -- >" + subjectForSSQ.getMsg());
    }
  }
}

看一个测试代码:

package com.zhy.pattern.observer.java; 

public class Test
{
  public static void main(String[] args)
  {
    SubjectFor3d subjectFor3d = new SubjectFor3d() ;
    SubjectForSSQ subjectForSSQ = new SubjectForSSQ() ; 

    Observer1 observer1 = new Observer1();
    observer1.registerSubject(subjectFor3d);
    observer1.registerSubject(subjectForSSQ); 

    subjectFor3d.setMsg("hello 3d'nums : 110 ");
    subjectForSSQ.setMsg("ssq'nums : 12,13,31,5,4,3 15"); 

  }
}

测试结果:

subjectFor3d's msg -- >hello 3d'nums : 110
subjectForSSQ's msg -- >ssq'nums : 12,13,31,5,4,3 15

可以看出,使用Java内置的类实现观察者模式,代码非常简洁,对了addObserver,removeObserver,notifyObservers都已经为我们实现了,所有可以看出Observable(主题)是一个类,而不是一个接口,基本上书上都对于Java的如此设计抱有反面的态度,觉得Java内置的观察者模式,违法了面向接口编程这个原则,但是如果转念想一想,的确你拿一个主题在这写观察者模式(我们自己的实现),接口的思想很好,但是如果现在继续添加很多个主题,每个主题的ddObserver,removeObserver,notifyObservers代码基本都是相同的吧,接口是无法实现代码复用的,而且也没有办法使用组合的模式实现这三个方法的复用,所以我觉得这里把这三个方法在类中实现是合理的。

(0)

相关推荐

  • 学习Java设计模式之观察者模式

    观察者模式:对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象(被观察). 以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并发生相应的变化. 观察者模式有很多实现方式:该模式必须包含观察者和被观察对象两种角色.观察者和被观察者之间存在"观察"的逻辑关系,当被观察者发生改变的时候,观察者就会观察到这样的变化,发出相应的改变. /** * 观察者接口:观察者,需要用到观察者模式的类需实现此接口 */ public interface Observer { pu

  • 深入解析Java设计模式编程中观察者模式的运用

    定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新. 类型:行为类模式 类图: 在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化.比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单:再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中.这两个功能有一个相似的地方,那就是一个对象

  • 实例解析观察者模式及其在Java设计模式开发中的运用

    一.观察者模式(Observer)的定义: 观察者模式又称为订阅-发布模式,在此模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知.这通常透过呼叫各观察者所提供的方法来实现.此种模式通常被用来事件处理系统. 1.观察者模式的一般结构 首先看下观察者模式的类图描述: 观察者模式的角色如下: Subject(抽象主题接口):定义了主题类中对观察者列表的一系列操作, 包括增加,删除, 通知等. Concrete Subject(具体主题类): Observer(抽象

  • java设计模式之观察者模式

    观察者模式又称发布-订阅(Publish/Subscribe)模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己.将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性.我们不希望为了维持一致性而使各类紧密耦合,这样会给维护.扩展和复用都带来不便.观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体. 观察者模式是实际中应用比较广泛的模

  • Java经典设计模式之观察者模式原理与用法详解

    本文实例讲述了Java经典设计模式之观察者模式.分享给大家供大家参考,具体如下: 观察者模式:对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象(被观察). 以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并发生相应的变化. 观察者模式有很多实现方式:该模式必须包含观察者和被观察对象两种角色.观察者和被观察者之间存在"观察"的逻辑关系,当被观察者发生改变的时候,观察者就会观察到这样的变化,发出相应的改变. /** * 观察者接口:观察者,需要用到观察者模式的

  • Java设计模式开发中使用观察者模式的实例教程

    观察者模式是软件设计模式中的一种,使用也比较普遍,尤其是在GUI编程中.关于设计模式的文章,网络上写的都比较多,而且很多文章写的也不错,虽然说有一种重复早轮子的嫌疑,但此轮子非彼轮子,侧重点不同,思路也不同,讲述方式也不近相同. 关键要素 主题: 主题是观察者观察的对象,一个主题必须具备下面三个特征. 持有监听的观察者的引用 支持增加和删除观察者 主题状态改变,通知观察者 观察者: 当主题发生变化,收到通知进行具体的处理是观察者必须具备的特征. 为什么要用这种模式 这里举一个例子来说明,牛奶送奶

  • java设计模式之观察者模式学习

    1.什么是观察者模式 简单情形:有A.B.C.D等四个独立的对象,其中B.C.D这三个对象想在A对象发生改变的第一时间知道这种改变,以便做出相应的响应或者对策. 上面的这种情形,就是观察者模式. 当然可以有多个观察者,多个被观察者. 观察者与被观察者也不是对立的,一个对象可以观察其他对象,也可以被其他对象观察. 2.观察者模式的应用 为了更好的理解什么是观察者模式,下面我举一些可能用到该模式的情形或例子: (1)周期性任务.比如linux中的周期性任务命令crontab命令,win7下的定时关机

  • Java设计模式之观察者模式_动力节点Java学院整理

    定义:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新. 类型:行为类模式 类图: 在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化.比如,我们要设计一个右键菜单的功能,只要在软件的有效区域内点击鼠标右键,就会弹出一个菜单:再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中.这两个功能有一个相似的地方,那就是一个对象

  • Java设计模式之观察者模式(Observer模式)介绍

    Java深入到一定程度,就不可避免的碰到设计模式(design pattern)这一概念,了解设计模式,将使自己对java中的接口或抽象类应用有更深的理解.设计模式在java的中型系统中应用广泛,遵循一定的编程模式,才能使自己的代码便于理解,易于交流,Observer(观察者)模式是比较常用的一个模式,尤其在界面设计中应用广泛,而本教程所关注的是Java在电子商务系统中应用,因此想从电子商务实例中分析Observer的应用. 虽然网上商店形式多样,每个站点有自己的特色,但也有其一般的共性,单就"

  • 用Java设计模式中的观察者模式开发微信公众号的例子

    还记得警匪片上,匪徒们是怎么配合实施犯罪的吗?一个团伙在进行盗窃的时候,总有一两个人在门口把风--如果有什么风吹草动,则会立即通知里面的同伙紧急撤退.也许放风的人并不一定认识里面的每一个同伙:而在里面也许有新来的小弟不认识这个放风的.但是这没什么,这个影响不了他们之间的通讯,因为他们之间有早已商定好的暗号. 呵呵,上面提到的放风者.偷窃者之间的关系就是观察者模式在现实中的活生生的例子. 观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式.GOF给观察者模式如下

  • 记录Yii2框架开发微信公众号遇到的问题及解决方法

    微信公众号开发,提示"该公众号暂时无法提供服务,请稍后再试",如何解决? 以前使用Yii框架的时候,并没有像Yii2,以前的Yii框架似乎用起来在安全方面不如Yii2,后面在用Yii2的时候发现了一个有趣的事情. 以前在用Yii框架做微信方面的开发的时候,开发模式需要添加对应的接口. 这里一定要注意点的点是在做接口验证的时候是使用GET请求,这个毫无疑问没有任何问题,但是在验证完之后,进行接口上面的交互的时候就有问题了,使用的POST的请求. 如果是以前的Yii的话,如果没有做严格的p

  • 详解NodeJs开发微信公众号

    古话说: 万事开头难, 回头细想想还真是这样,在没有开始做微信公众号开发之前我以为它很复杂,但是学过之后只想说原来just so so~ 这里是我的项目的github地址: https://github.com/muzishuiji/wechat 下面我就把我的学习过程做一下总结,希望可以帮助到有需要的人儿.粗鄙之见,恐有不足,欢迎指教(PS: 在阅读下文之前,你应该对NodeJs和koa框架有一定的了解,会编写简单的项目,如果不是,建议你暂放这篇文章,来这里看看)! 我把我们这次的学习之旅比做

  • java开发微信公众号支付

    最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时间,也只是达到了实现功能的水平,并没有太多考虑到性能问题,所以这篇文章比较适合初学者. 微信公众号支付的总体其实很简单,大致就分为三步.第一步需要获取用户授权:第二步调用统一下单接口获取预支付id:第三步H5调起微信支付的内置的js.下面介绍具体每一步的开发流程. 一    首先要明确微信公众号支付属于网页版支付,所以相较于app的直接调取微信支付要多一步微信授权.也就是需要获取用户的openid.微信公众号使用的交易类型是JSAPI,

  • Java开发微信公众号接收和被动回复普通消息

    上篇说完了如何接入微信公众号,本文说一下微信公众号的最基本功能:普通消息的接收和回复.说到普通消息,那么什么是微信公众号所定义的普通消息呢,微信开发者文档中提到的接收的普通消息包括如下几类: 1.文本消息 2.图片消息 3.语音消息 4.视频消息 5.小视频消息 6.地理位置消息 7.链接消息(被动回复的消息) 被动回复的普通消息包括: 1.回复文本消息 2.回复图片消息 3.回复语音消息 4.回复视频消息 5.回复音乐消息 6.回复图文消息 其实接收消息和被动回复消息这两个动作是不分家的,这本

  • 使用Nodejs开发微信公众号后台服务实例

    摘要: 微信,庞大的用户基数,极强的用户粘性,在近两年吸引了无数的开发者注意力. Nodejs,近两年发展非常快的开发工具,尤其适合构建移动后台.本文就以笔者自己开发的实例,来描述如何基于Nodejs开发属于自己的微信公众号.在这个实例中,主要使用到了express, wechat, mongodb, monk等模块. 前期准备: 1.申请微信公众号,前往 https://mp.weixin.qq.com/  申请,这里不做过多阐述. 2. 购买服务器, 这里推荐Amazon的EC2,首次用户可

  • 使用NodeJs 开发微信公众号(三)微信事件交互实例

    微信公众号有个规则,一旦开启了开发者模式,其他的常规功能就都必须通过接口调用完成.比如说自定义菜单功能,必须通过发送post请求的方式生成.本章就通过关注到取消关注的整个过程来谈一谈nodejs是怎么样与微信交互的.这些功能的入口就是你在测试公众号里面填写的URL(以下用/login/wechat代替). 事件交互 扫码关注微信公众号后,微信会调用你的接口/login/wechat,并且附带一段xml信息,首先你需要获取一些签名,通过加密.排序比对是否与你填写的TOKEN一致,如果一致则进行xm

  • C#开发微信公众号接口开发

    具体实现方式不多说了,请看下文 一.前言 当下微信公众号几乎已经是每个公司必备的,但是大部分微信公众账号用户体验都欠佳,特别是涉及到用户绑定等,需要用户进行复杂的操作才可以和网站绑定,或者很多公司直接不绑定,而是每次都让用户填写账号密码.作为微信接口开发人员我们知道网页授权可以用作微信网页用作安全登录,带参数二维码的使用用作记录用户来源,模板消息用作购物消费等消息的通知,但是很少看到有综合利用这些高级接口做出体验比较好的公众账号,这里分享一些我开发的用户绑定和验证码的一些心得.所需要的接口有基础

  • java微信公众号开发(搭建本地测试环境)

    俗话说,工欲善其事,必先利其器.要做微信公众号开发,两样东西不可少,那就是要有一个用来测试的公众号,还有一个用来调式代码的开发环境. 测试公众号 微信公众号有订阅号.服务号.企业号,在注册的时候看到这样的信息,只有订阅号可以个人申请,服务号和企业号要有企业资质才可以.这里所说的微信公众号开发指的是订阅号和服务号. 另外,未认证的个人订阅号有一些接口是没有权限的,并且目前个人订阅号已不支持微信认证,也就是说个人订阅号无法调用一些高级的权限接口,下图就是一个未认证的个人订阅号所具备权限列表,像生成二

  • 微信公众号开发客服接口实例代码

    最近,开发微信公众号,负责开发客服功能,这里简单记录下: Kf_account.cs代码: public partial class Kf_account : Form { private readonly DataTable adt_user = new DataTable(); private readonly string as_INIFile = Application.StartupPath + "\\user.ini"; public Kf_account() { Bind

随机推荐