文档章节

java设计模式-观察者模式

fengsehng
 fengsehng
发布于 2016/11/09 09:12
字数 1673
阅读 2
收藏 0
点赞 0
评论 0

定义:

使用head First 设计模式中提到的说法

观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监听一个主题对象。这样一来,当被观察者状态发生改变时,需要通知相应的观察者,使这些观察者对象能够自动更新。

简介:

观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。

面向对象设计的一个原则是:

系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

实现方式

实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

组成元素:

主题

主题是观察者观察的对象,一个主题必须具备下面三个特征。

持有监听的观察者的引用
支持增加和删除观察者
主题状态改变,通知观察者

观察者

当主题发生变化,收到通知进行具体的处理是观察者必须具备的特征。

1.自定义实现例子:

这里写图片描述

代码:(使用了泛型和反射)

//观察者,需要用到观察者模式的类需实现此接口
public interface Observer{
    void update(Object...objs);
}

//被观察者(一个抽象类,方便扩展)
public abstract class Observable{

    public final ArrayList<Class<?>> obserList = new ArrayList<Class<?>>();

    /**AttachObserver(通过实例注册观察者) *<b>Notice:</b>obcan'tbenull,oritwillthrowNullPointerException **/
    public<T> void registerObserver(T ob){
        if(ob==null) throw new NullPointerException();
        this.registerObserver(ob.getClass());
    }

    /** *AttachObserver(通过Class注册观察者) *@paramcls */
    public void registerObserver(Class<?> cls){
        if(cls==null) throw new NullPointerException();
        synchronized(obserList){
            if(!obserList.contains(cls)){
                obserList.add(cls);
            }
        }
    }

    /**UnattachObserver(注销观察者) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/
    public<T>void unRegisterObserver(Tob){
        if(ob==null) throw new NullPointerException();
        this.unRegisterObserver(ob.getClass());
    }

    /**UnattachObserver(注销观察者,有时候在未获取到实例使用) *<b>Notice:</b> *<b>ItreverseswithattachObserver()method</b> **/
    public void unRegisterObserver(Class<?>cls){
        if(cls==null) throw new NullPointerException();
        synchronized(obserList){
            Iterator<Class<?>>iterator=obserList.iterator();
            while(iterator.hasNext()){
                if(iterator.next().getName().equals(cls.getName())){
                    iterator.remove();
                    break;
                }
            }
        }
    }

    /**detachallobservers*/
    public void unRegisterAll(){
        synchronized(obserList){
            obserList.clear();
        }
    }

    /**Ruturnthesizeofobservers*/
    public int countObservers(){
        synchronized(obserList){
            returnobserList.size();
        }
    }

    /** *notify all observer(通知所有观察者,在子类中实现) *@paramobjs */
    public abstract void notifyObservers(Object... objs);

    /** *notify one certain observer(通知某一个确定的观察者) *@paramcls *@paramobjs */
    public abstract void notifyObserver(Class<?> cls, Object... objs);

    /** *notifyonecertainobserver *@paramcls *@paramobjs */
    public abstract<T> void notifyObserver(T t, Object... objs);
}

//目标被观察者
public class ConcreteObservable extends Observable{

    private static ConcreteObservableinstance = null;
    private ConcreteObservable(){};
    public static synchronized ConcreteObservablegetInstance(){
        if(instance == null){
            instance=newConcreteObservable();
        }
        returninstance;
    }

    @Override
    public <T> void notifyObserver(T t, Object... objs){
        if(t == null) throw new NullPointerException();
        this.notifyObserver(t.getClass(), objs);
    }

    @Override
    public void notifyObservers(Object... objs){
        for(Class<?>cls : obserList){
            this.notifyObserver(cls, objs);
        }
    }


    //通过java反射机制实现调用
    @Override
    public void notifyObserver(Class<?>cls, Object...objs){
        if(cls == null) throw new NullPointerException();
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            if(method.getName().equals("update")){
                try{
                    method.invoke(cls,objs);
                    break;
                }catch(IllegalArgumentException e){
                    e.printStackTrace();
                }catch(IllegalAccessException e){
                    e.printStackTrace();
                }catch(InvocationTargetException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

//使用(实现Observer接口)
public class Text extends Activity implements Observer{
    publicvoidonCreate(...){
        ConcreteObservable.getInstance().registerObserver(Text.class);
        ....
    }

    //实现接口处理
    publicvoidupdate(Object...objs){
        //做操作,比如更新数据,更新UI等
    }
}

2.java内置的实现方式:

java.util.Observable 这是一个类,而非接口,主题需要继承这个类。

java.util.Observer 这是一个接口,监听者需要实现这个接口。

代码:

import java.util.Observable;
import java.util.Observer;
public class MainRoot {
  public static void main(String[] args) {
      Observer consumer = new Consumer();
      MilkProvider provider = new MilkProvider();
      provider.addObserver(consumer);
      provider.milkProduced();
  }

  static class MilkProvider extends Observable {
      public void milkProduced() {
          setChanged();//状态改变,必须调用
          notifyObservers();
      }
  }

  static class Consumer implements Observer {
      @Override
      public void update(Observable arg0, Object arg1) {
          System.out.println("Consumer update..." + arg0 + ";arg1=" + arg1);
      }
  }
}

setChange讲解

源代码:

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

setChange的意义:

1.筛选有效通知,只有有效通知可以调用setChanged。比如,我的微信朋友圈一条状态,好友A点赞,后续该状态的点赞和评论并不是每条都通知A,只有A的好友触发的操作才会通知A。

2.便于撤销通知操作,在主题中,我们可以设置很多次setChanged,但是在最后由于某种原因需要取消通知,我们可以使用clearChanged轻松解决问题。

3.主动权控制,由于setChanged为protected,而notifyObservers方法为public,这就导致存在外部随意调用notifyObservers的可能,但是外部无法调用setChanged,因此真正的控制权应该在主题这里。

如何主动获取通知:

需要主题为某些数据提供getter方法,观察者只需调用getter取数据处理即可。

代码:

static class MilkProvider extends Observable {
    public void milkProduced() {
      setChanged();//状态改变,必须调用
      notifyObservers();
    }

    public float getPrice() {
      return 2.5f;
    }
  }

  static class Consumer implements Observer {
    @Override
    public void update(Observable arg0, Object arg1) {
        MilkProvider provider = (MilkProvider)arg0;
        System.out.println("milk price =" + provider.getPrice());
    }
  }

观察者模式的优点:

1.观察者增加或删除无需修改主题的代码,只需调用主题对应的增加或者删除的方法即可。

2.主题只负责通知观察者,但无需了解观察者如何处理通知。

3.观察者只需等待主题通知,无需观察主题相关的细节。

4.由于被动接受,正常情况下不会错过主题的改变通知。而主动获取的话,由于时机选取问题,可能导致错过某些状态。

缺点:

1.主题持有观察者的引用,如果未正常处理从主题中删除观察者,会导致观察者无法被回收。

2.如果观察者具体实现代码有问题,会导致主题和观察者对象形成循环引用,在某些采用引用计数的垃圾回收器可能导致无法回收。

我的微信二维码如下,欢迎交流讨论

这里写图片描述

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

这里写图片描述

参考:

http://baike.baidu.com/view/1854779.htm
http://droidyue.com/blog/2015/06/27/desgign-pattern-observer/index.html

© 著作权归作者所有

共有 人打赏支持
fengsehng
粉丝 4
博文 284
码字总数 214494
作品 0
朝阳
程序员
20个设计模式和软件设计面试问题

不管是参加Java面试还是C#面试,设计模式和软件设计都是任何编程面试中的必问问题。实际上,编程能力和设计技巧是对彼此很好的补充。一个好的程序员通常都是一个好的软件设计人员。他们知道怎...

LCZ777
2014/08/13
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0
设计模式15——Template Method设计模式

Template Method模板方法设计模式定义一个操作中算法的骨架,将具体步骤的执行延迟到子类中实现。Java中的抽象类就是使用了模板方法设计模式。模板方法设计模式结构如下: 以文档处理为例,T...

小米米儿小
2014/01/24
0
0
设计模式3——Proxy设计模式

Proxy代理设计模式是一种控制对象访问的设计模式,类似于网络代理,网络代理机制如下图: Proxy代理设计模式机制如下: 代理模式UML图如下: 代理模式顺序图如下: 客户端程序通过代理程序来...

小米米儿小
2013/12/06
0
0
简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别

转载:原地址http://www.cnblogs.com/zhangchenliang/p/3700820.html 简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别 结合简单示例和UML图,讲解工厂模式简单原理。 一、引子 话说...

法斗斗
05/08
0
0
Java设计模式 create FactoryMethod

工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经...

神勇小白鼠
2011/05/18
0
0
23种设计模式(1):单例模式

定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 类型:创建类模式 类图: 类图知识点: 1.类图分为三部分,依次是类名、属性、方法 2.以<<开头和以>>结尾的为注释...

LCZ777
2014/07/05
0
0
groovy 闭包【命令模式】

在Java编程世界,有两个设计模式又简单、又常用,而且实现方式也很相似,这就是命令模式和策略模式。 有关这两个模式的讲解,在网络上真是汗牛充栋,大家可以随便搜索一下,就是一大堆。 可以...

k_k_anna
2015/01/20
0
0
为什么java中用枚举实现单例模式会更好

枚举单例是java中使用枚举提供一个实例对象来实现单例模式的一种新方法,虽然单例模式在java中早已存在,但枚举单例实际上从java5引入枚举作为它的关键特性之后相对来说还是一个新的概念,这...

zhoujy
2013/06/01
0
0
JavaScript设计模式系列三之单例模式(附案例源码)

文章初衷 设计模式其实旨在解决语言本身存在的缺陷 目前javaScript一些新的语法特性已经集成了一些设计模式的实现, 大家在写代码的时候,没必要为了用设计模式而去用设计模式, 那么我这边为什...

小钱钱阿圣
2017/09/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

打印斐波那契数

package com.jerry.ch04;public class PrintFibonacci {public static void main(String[] args) {for (int i=0; i<10; i++) {System.out.print(fib(i) + " ");}......

JerryNing
11分钟前
0
0
shell编程

一、shell脚本介绍

人在艹木中
12分钟前
0
0
istio 0.8 遥测 案例

==============遥测===================================== 演示如何从网格中收集遥测信息。 分布式跟踪。如何配置代理以向Zipkin或Jaeger发送跟踪请求 收集度量标准和日志。此任务说明如何配...

xiaomin0322
14分钟前
0
0
ND4J求多元线性回归以及GPU和CPU计算性能对比

上一篇博客《梯度下降法求多元线性回归及Java实现》简单了介绍了梯度下降法,并用Java实现了一个梯度下降法求回归的例子。本篇博客,尝试用dl4j的张量运算库nd4j来实现梯度下降法求多元线性回...

冷血狂魔
15分钟前
0
0
springboot常用注解

@SpringBootApplication: 包含@Configuration、@EnableAutoConfiguration、@ComponentScan 通常用在主类上。 @Service: 用于标注业务层组件。 @RestController: 用于标注控制层组件(如strut...

GoldenVein
21分钟前
1
0
如何进行大数据的入门级学习?

不知道你是计算机专业应届生还是已经从业者。总之,有java基础的学生学习大数据会轻松很多,零基础的小白都需要从java和linux学起。 如果你是一个学习能力特别强,而且自律性也很强的人的话可...

董黎明
35分钟前
0
0
使用Parcelable传递复杂参数

最近做AIDL传递对象,对象必须实现Parcelable的方法才可以被传递。 @Override    public int describeContents() {//这个 默认返回0就行了。        return 0;    }    ...

火云
36分钟前
0
0
十大Intellij IDEA快捷键

Intellij IDEA中有很多快捷键让人爱不释手,stackoverflow上也有一些有趣的讨论。每个人都有自己的最爱,想排出个理想的榜单还真是困难。以前也整理过Intellij的快捷键,这次就按照我日常开发...

HJCui
46分钟前
0
0
word 使用mathtype 编写 数学公式

下载安装,这个链接命名。。。。 http://www.mathtype.cn/xiazai.html 安装之后会多出一个选项 使用内联方式插入图表 编写公式的界面 设置支持latex 语法 输入公式回车就可以看到结果...

阿豪boy
今天
0
0
Promise

定义 Promise是异步编程的一种解决方案,所谓Promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个一步操作)的结果。 特点: 2.1 对象的状态不受外界影响,三种状态pending...

litCabbage
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部