新手码农浅谈观察者模式(java语言简单实现)

一:什么是观察者模式:

官方定义:定义对象间一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

举个例子,很多人都会订阅天气预报,当气象台获得明天的天气情况(目标对象)时,就会短信通知订阅了天气预报的人(观察者),然后订阅者就会根据明天天气情况做出相应的处理(呆在家?出去踏青?出去购物...)

二:观察者模式的两个角色:

第一个角色:目标对象(subject),被观察者关注的对象,它的改变引起观察者的改变,例如上面提到的天气情况。

第二个角色:观察者(observer),一个或者多个,关注着目标对象的状态,例如上例的订阅了天气预报的人群。

三:观察者模式三种常见的角色场景:

1. 一个目标对象,一个观察者对象,比如只要你一个人订阅了天气预报

2. 一个目标对象,多个观察者对象,比如,你爸爸,你妈妈和你都订阅了天气预报

3. 多个目标对象,一个观察者对象,比如你一个人订阅了天气预报,还订阅了报纸

四:推模型和拉模型(后面的代码会有注释):

推模型:observer在执行update()方法时,获取的是subject传给它的具体参数,目标对象主动向观察者推送目标的详细信息。

拉模型:observer在执行update()方法时,获得的是subject传给它的一个subject对象,observer需要什么参数自己去取。

五:java代码实行观察者模式:

首先提供最基本的观察者模式代码框架:

1. 新建一个Subject父类

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

/*
 * 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口
 */
public class Subject {
    //用来保存注册的观察者对对象
    private List<Observer> observers = new ArrayList<Observer>();

    //将观察者添加多list对象中
    public void attch(Observer observer){
         observers.add(observer);
    }

    //删除集合中的指定观察者对象
    public void delete(Observer observer){
        observers.remove(observer);
    }

    //向所有注册了的观察者通知消息
    protected void notifyObserver() {
        for(Observer observer:observers){
            observer.update(this);
        }
    }
}

2. 新建一个具体Subject实现类

/*
 * 具体的目标对象,负责把有关状态存入到相应的观察者对象
 */
public class ConcreteSubject extends Subject {
    //目标对象的状态
    private String subjectState;

    public String getSubjectState() {
        return subjectState;
    }

    public void setSubjectState(String subjectState) {
        this.subjectState = subjectState;
        this.notifyObserver();
    }

}

3. 新建一个Observer接口

/*
 * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象
 */
public interface Observer {

    /*
     * 更新接口
     * subject传入的目标对象,方便获取目标对象的状态
     */
    public void update(Subject subject);

}

4. 新建一个observer实现类

/*
 * 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致
 */
public class ConcreteObserver implements Observer {

    private String observerState;
    @Override
    public void update(Subject subject) {
        // TODO Auto-generated method stub
        observerState = ((ConcreteSubject)subject).getSubjectState();
    }

}

下面我用一个具体的例子,来实现观察者模式,让你更加清晰了解观察者模式

一个这样的场景,小东的女朋友和老妈都订阅了小东开发的一个天气预报软件,当每天天气不同时,小东的女朋友和老妈收到天气情况通知,都会安排明天的行程。小东的这个软件可逗的女朋友和老妈开心了,原来程序猿还有这作用,下面来看程序如何演示的:

1. 新建一个WeatherSubject父目标对象

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

/*
 * 目标对象,他知道观察它的观察者,并提供注册(添加)和删除观察者的接口
 */
public class WeatherSubject {
    //用来保存订阅天气的人
    private List<Observer> observers = new ArrayList<Observer>();

    //把订阅天气的人添加到订阅列表中
    public void attch(Observer observer){
         observers.add(observer);
    }

    //删除集合中的指定的订阅天气的人
    public void delete(Observer observer){
        observers.remove(observer);
    }

    //通知所有已经订阅了天气的人
    protected void notifyObserver() {
        for(Observer observer:observers){
            observer.update(this);
        }
    }
}

2. 新建一个WeatherSubject具体实现对象( 观察者需要从目标对象中需要获取的的状态只有天气内容)

/*
 * 具体的目标对象,负责把有关状态存入到相应的观察者对象
 */
public class ConcreteWeatherSubject extends WeatherSubject {
    //获取天气的内容信息
    private String weatherContent;

    public String getWeatherContent() {
        return weatherContent;
    }

    public void setWeatherContent(String weatherContent) {
        this.weatherContent = weatherContent;
        //内容有了,说明天气更新了,通知所有订阅的人
        this.notifyObserver();
    }

}

3. 新建一个Observer接口

/*
 * 这是一个观察者接口,定义一个更新的接口给那些在目标发生改变时,被通知的对象
 */
public interface Observer {

    /*
     * 更新接口
     * subject传入的目标对象,方便获取目标对象的状态
     */
    public void update(WeatherSubject subject);

}

4. 新建一个具体的WeatherSubject对象

/*
 * 具体的观察者对象,实现更新的方法,使自身状态和目标状态一致
 */
public class ConcreteObserver implements Observer {

    //观察者的名字,是谁收到了这个讯息,小东女朋友还是他老妈
    private String observerName;

    //天气内容的情况,这个消息从目标处获得
    private String weatherContent;

    //提醒的内容,小东的女朋友提醒约会,而他老妈提醒购物
    private String remindThing;

    public String getObserverName() {
        return observerName;
    }
    public void setObserverName(String observerName) {
        this.observerName = observerName;
    }
    public String getWeatherContent() {
        return weatherContent;
    }
    public void setWeatherContent(String weatherContent) {
        this.weatherContent = weatherContent;
    }
    public String getRemindThing() {
        return remindThing;
    }
    public void setRemindThing(String remindThing) {
        this.remindThing = remindThing;
    }

    public void update(WeatherSubject subject) {
        weatherContent = ((ConcreteWeatherSubject)subject).getWeatherContent();
       System.out.println(observerName + "收到了" + weatherContent + ","+remindThing);
    }

}

5. 测试类

public class Client {
   public static void main(String[] args) {
    //1.创建目标
       ConcreteWeatherSubject weatherSubject = new ConcreteWeatherSubject();

    //2.创建观察者
       ConcreteObserver observerGirl = new ConcreteObserver();
       observerGirl.setObserverName("小东的女朋友");
       observerGirl.setRemindThing("是我们的第一次约会,地点华罗利广场,不见不散额");

       ConcreteObserver observerMom = new ConcreteObserver();
       observerMom.setObserverName("小东的老妈");
       observerMom.setRemindThing("是一个购物的好日子,明天去老街血拼");
    //3.注册观察者
       weatherSubject.attch(observerGirl);
       weatherSubject.attch(observerMom);

    //4.目标发布天气
       weatherSubject.setWeatherContent("明天天气晴朗,晴空万里,温度28℃");
   }
}

6. 运行结果

各位程序猿屌丝们,原来观察者模式还能来泡妞,你还等什么了,现在对观察者模式有了基本的了解了吧。最后我们来谈谈哪些情况能用到观察者模式:

  • 当一个抽象模型有两个方面,其中一个方面的操作依赖与另一方面的状态变化就可以使用观察者模式。
  • 如果在更改一个状态的时候,需要同事连带改变其他对象,而且不知道有多少个对象需要被连带改变时,可以选用观察者模式。
  • 当一个对象必须通知其它对象,但你又希望这个对象和其它被它通知的对象是松散耦合的,也可以使用观察者模式。

谢谢各位看官的赏脸,我们下次再见!

时间: 2024-10-12 22:20:55

新手码农浅谈观察者模式(java语言简单实现)的相关文章

浅谈对Java中ThreadLocal类的理解

首先要明确:ThreadLocal不是一个多线程类,或者应该叫做线程局部变量.这从ThreadLocal的JDK定义中就可以看到 public class ThreadLocal<T>extends Object 可以看出ThreadLocal只是一个普普通通的类,并没有继承自Thread或实现Runnable接口. 同时也可以看到ThreadLocal使用了泛型,这样他就可以操作几乎任何类型的数据了.下面说JDK API代码时具体再说. 对此类,看看JDK API中的部分描述: 该类提供了线

浅谈一下java基础需要掌握的知识点

大学四年浑浑噩噩就过去了,找工作才发现自己欠的太多,没办法来培训了,一个月的java基础已经结束,来总结下自己对java基础的看法. java语言是一个面向对象的过程,学习java不能把代码看成一串串的英文字母,应该把它们想象成现实中具体的对象,譬如要用java编写出你去饭店吃饭,这就至少需要定义你和厨师两个对象类,你点餐,吃饭,付账就是你自己对象类里面的方法,做饭,洗漱餐具就是厨师对象类里面的方法. java基础是java方向的地基,在刚开始学习时很多时候我们会感觉没意思,因为没有一个成品,都

浅谈C++/JAVA/C#运行机制和执行效率

估计有很多同学都对C++/JAVA/C#这三大热门语言的运行机制和执行效率有或多或少的困惑,自己也有,但是经过前期的学习,了解了三者在这两方面的区别,就废话不说了,进入主题吧. 一.运行机制 1.JAVA-编译和解释型语言 一个JAVA文件,首先会由JAVA编译器(JAVAC)编译成class(字节码文件)文件,然后由Java虚拟机(JVM)去解释.不同的操作系统只要装有适合不同平台的JDK,JAVA文件都可以被解释运行.JAVA是一种编译和解释型语言.       字节码文件(class)之所

剖析源码:浅谈react-infinite的机制与原理

最近又读了一个轮子的源码,react-infinite,虽然star数量不是特别多,1.5k,不过还是个非常实用的轮子,今天给大家讲的是它的原理和实现,并不是如何去使用它,如何使用官方文档上都有.了解了它的原理,你就不一定要全盘使用它,你可以自己剥离一部分实际要用的东西出来,自己写一个合适的轮子用到项目中去(不要为了一个功能去使用一整个框架或者插件). 说了那么多废话,它是用来干嘛的? 官方解释:A browser-ready efficient scrolling container base

浅谈 c++/java/javascript 之传参

本文主要梳理了几种语言的传参机制,即关于 传值.传引用 之争 最近开始学node.js搭后端服务器时,碰到这样一句话 java只有一种传参机制就是传值 javascript其大部分语法规范取自于JAVA语法规范, 那么这种句话也适用于它,于是也有  javascript只有一种传参机制就是传值 为了理解这句话,我从个人感觉较为接近底层的语言c++写一些测试,代码如下 #include<iostream> using namespace std; class Test { public: int

浅谈PL/SQL语言基础

在前面的学习中,我们大部分接触的都是SQL语言,但是,在实现复杂操作的时候,SQL语言就无能为力了,这时候就需要引入新的语言,PL/SQL语言就是对SQL语言的扩展,可以实现存储过程,函数等的创建.下面是我对PL/SQL语言的总结,和大家分享一下. 一.基本结构 1.PL/SQL是一种块结构的语言,它将一组语句放在一个块中,一次性发送给服务器,当PL/SQL引擎分析收到PL/SQL语句块中的内容,把其中的过程语句由PL/SQL引擎自身去执行,把PL/SQL语句块中的SQL语句交给服务器的SQL语

浅谈用java解析xml文档(四)

继续接上一文,这一阵子因为公司项目加紧,导致最后一个解析xml文档的方式,还没有总结,下面总结使用dom4J解析xml. DOM4J(Document Object Model for Java) 使用dom4j解析,个人认为是四种解析方式里面最方便的一种,DOM4J是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件.如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用D

浅谈用java解析xml文档(三)

接上一篇,本文介绍使用JDOM解析xml文档, 首先我们还是应该知道JDOM从何而来,是Breet Mclaughlin和Jason Hunter两大Java高手的创作成果,2000年初, JDOM作为一个开放源代码项目正式开始研发.JDOM是一种解析XML的Java工具包. JDOM基于树状结构,利用纯JAVA技术对XML文档实现解析.生成.序列化及其它操作. 我们从以下步骤开始解析: (1).通过JDOM的API创建一个SAXBuilder的对象 SAXBuilder saxBuilder

金九银十,浅谈关于java程序员面试的一些事项

本篇博文针对的是应届毕业生以及工作两三年左右的java程序员. 为什么要跳槽? 这是一个很广义的问题,每个人心中都有一份答案. 例如: 公司的待遇不好, 薪资涨幅不符合预期要求, 厌倦了出差的荒无天日的繁重工作, 公司的妹子太少, 领导太傲娇, 同事之间关系太逼格, 某某同学跳槽到某某公司之后涨到了多少多少钱, 某某同学的朋友的同事的三姑妈家的大儿子的好基友在某某高就, 等等辞职理由. 咱们就不多说了,还是谈谈怎么应付面试吧. 以下内容是我在面试中总结的一些经验,希望这些可以给各位带来帮助和启迪