Observer模式

java的设计模式


作用 当观察对象的状态发生变化时,通知给观察者(观察者订阅被观察者的状态)
应用 需要根据对象状态进行相应处理的场景

Observer.png

创建Subject类

package com.company;

import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;

public abstract class Subject{

    private ArrayList observers = new ArrayList();//保存Observer们
    public void addObserver(Observer observer){
        observers.add(observer);
    };//注册Obeserver
    public void notifyObservers(){
        //向Observer发送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            Observer observer = (Observer)it.next();
            observer.update();
        }
    }
    public abstract int getState();
    public abstract void setState();\\写成抽象方法,便于拓展
}

Subject的子类

package com.company;

import java.util.Random;

public class Subjecta extends Subject{
    private int number;
    private Random random = new Random();

    @Override
    public int getState() {
        return number;
    }

    @Override
    public void setState() {
        for(int i = 0 ;i < 10 ;i++){
            number = random.nextInt(48);
            notifyObservers();
        }
    }
}

创建抽象Observer类

package com.company;

public abstract class Observer {
    protected Subject subject;\\有Subject类的实例化对象,便于获取被观察者的信息
    public abstract void update();\\在子类中实现更新的具体操作
}

创建实体观察类

package com.company;

public class Observera extends Observer{
    public Observera(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);
    }

    @Override
    public void update() {
        System.out.println( "Observera : " + subject.getState());
    }
}

public class Observerb extends Observer{
    public Observerb(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);
    }

    @Override
    public void update() {
        System.out.print("Observerb : ");
        for(int i = 0 ;i< subject.getState();i++) {
            System.out.print('-');
        }
        System.out.println();
    }
}

在客户端(Main)使用

package com.company;

public class Main {

    public static void main(String[] args) {
        Subject subject = new Subjecta();
        new Observera(subject);
        new Observerb(subject);\\创建观察者

        subject.setState();\\设置状态(改变状态)
    }
}

另一种实现方法

  • 抽象Observer类变为为接口——ObserverI
  • Subject的实例化对象subject变成接口ObserverI的update()方法的参数(原来是抽象类Observer的私有成员)
package com.company;

public interface ObserverI {
    public abstract void update(Subject subject);
}
  • Observer类由抽象类变成了接口,Subject类中添加观察者的方法和向Observer发送通知的方法也应当重写
public abstract class Subject{

    private ArrayList observers = new ArrayList();//保存Observer们
    public void addObserver(Observer observer){
        observers.add(observer);
    };//第一种,注册obeserver

    public void addObserver(ObserverI observer){
        observers.add(observer);
    };//第二种方法,注册Obeserver的方式

    public void notifyObservers(){
        //向Observer发送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            Observer observer = (Observer)it.next();
            observer.update();
        }
    }//第一种

    public void notifyObservers2(){
        //向Observer发送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            ObserverI observer = (ObserverI)it.next();
            observer.update(this);//改变后的update方法需要传入一个subject进去
        }
    }//第二种方法
//注意:在状态改变后(setState)应当调用的发送通知的方法也应当换成第二种对应的
}

  • 继承ObserverI接口,实现具体方法
package com.company;

public class ObserverI1 implements ObserverI{
    @Override
    public void update(Subject subject) {
        System.out.println( "Observera : " + subject.getState());
    }
}

public class ObserverI2 implements ObserverI{
    @Override
    public void update(Subject subject) {
        System.out.print("Observerb : ");
        for(int i = 0 ;i< subject.getState();i++) {
            System.out.print('-');
        }
        System.out.println();
    }
}

  • 由于ObserverI接口只有抽象方法,在Observer的具体实现类中没有Subject类的实例化对象作为类成员,无法在构造函数中直接添加observer(注册observer),需要在客户端(Main)添加
//第一种注册observer的方式
public class Observerb extends Observer{
    public Observerb(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);//改变后
    }
}//第一种只要创建了Subject具体实现类的实例化对象,就在被观察者中添加了观察者,

//第二种方法,注册Observer的方式
public class Main {

    public static void main(String[] args) {
        Subject subject = new Subjecta();
        Observer observer1 = new Observera();
        Observer observer2 = new Observerb();//创建观察者
            subject.addObserver(observer1);
            subject.addObserver(observer2);
        subject.setState();\\设置状态(改变状态)
    }
}//现在,创建观察者后,还需调用被观察者中添加观察者的方法)

注意点

Observer的顺序

Subject角色中有多个Observer角色,在示例代码中是先注册的Observer的update方法先被调用

Observer的行为对Subject的影响

Subject的状态变化 ---> 通知Observer ---> Observer调用Subject的方法 ---> 导致Subject的状态发生变化 ---> 通知Observer
导致方法被循环调用

update方法传入的参数

void update(Subject subject); 
void update(int number);  
void update(Subject subject,int number); 

可以传入Subject实例对象,也可以传入该实例中的某些数据,第一种更加灵活

拓展
java.utill.Observer 接口
java.utill.Observable 类 ——被观察的Subject角色

 public void update(Observable obj,Object arg)//Object类的实例是附加信息

缺陷Subject角色必须是java.utill.Observable 类的子类,但是java是单一继承

以上完整的代码上传到了github仓库
https://github.com/chenshuyuhhh/DesignPatternDemo.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • 参考资料:菜鸟教程之设计模式 设计模式概述 设计模式(Design pattern)代表了最佳的实践,通常被有经验...
    Steven1997阅读 1,172评论 1 12
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,623评论 18 399
  • 1. 想起读这本书的源头是一部网络剧---《灵魂摆渡》,当初是冲着赵吏这个角色的扮演者于毅才开始看剧,我想每个人心...
    苏苏书书阅读 306评论 0 3
  • I:重述 WHAT: 这个片段讲述的是如何运用减压三步法得到全面的放松和休息。 WHY: 现在生活工作节奏不断加快...
    假装Yes阅读 147评论 0 0
  • 亲子日记第125篇 中午看到牛老师在家长群里发的她已经执教完成,现在已经在回家的路上了,我眼睛不知不觉就湿...
    一年级七班王烁桦妈妈阅读 141评论 0 1