设计模式之观察者模式

2021年9月13日 2点热度 0条评论 来源: carl的分享笔记

简介:

当一件事变化时,通知给所有需要知道的人
观察者模式主要包括观察者(需要知道的人)和被观察者(被观察的那件事)
行为型模式
观察者模式属于推的模式,观察者是被动接受的

类图:

示例:

被观察者:

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

/** * 被观察对象 */
public class Subject{ 
    // 观察者列表
    protected List<Observer> observers = new ArrayList<>();
    // 被观察的属性
    private int state;

    public int getState() { 
        return state;
    }
    public void setState(int state) { 
        this.state = state;
        // 在被观察的对象发生变化的地方通知所有人
        notifyAllObservers();
    }
    public void attach(Observer observer){ 
        observers.add(observer);
    }
//被观察者的通知所有人的方法 需要在事件发生时调用通知所有观察者
    public void notifyAllObservers(){ 
        for(Observer observer : observers){ 
            observer.update();
        }
    }
}

观察者:

/** * 观察者抽象类 只需要将观察者 和 被观察者建立联系就可以 */
public class Observer { 

    protected Subject subject ;
    // 观察者名称
    private String name;

    public Observer(Subject subject,String name){ 
        this.subject = subject;
        this.name = name;
        // 这里让观察者与被观察者建立联系
        this.subject.attach(this);
    }
// 观察者必须要有一个通知方法
    public void update(){ 
// TODO 这里实现业务逻辑
        System.out.println( name + "收到更新:" + subject.getState() );
    }

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }

}

调用:

public class Demo { 

    public static void main(String[] args) { 

        Subject subject = new Subject();
        new Observer(subject,"obA");
        new Observer(subject,"obB");

        subject.setState(12);
    }


}

JDK方式:

被观察者

import java.util.Observable;

/** * 被观察者 */
public class MySubject extends Observable { 


    // 被观察属性
    private int state;

    public int getState() { 
        return state;
    }

    public void setState(int state) { 
        this.state = state;
        // 标识事件发生了
        setChanged();
        // 在被观察对象发生变化时 通知所有观察者
        notifyObservers();
    }

}

观察者

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

/** * 观察者 */
public class MyObserver implements Observer { 
    //观察者名称
    private String name;

    public MyObserver(String name){ 
        this.name = name;
    }

    // 观察者必须要有一个通知方法
    @Override
    public void update(Observable o, Object arg) { 
        // TODO 这里实现业务逻辑
        MySubject b = (MySubject) o;
        System.out.println(name + "收到通知:" + b.getState());
    }

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }

}

调用

public class Demo { 

    public static void main(String[] args) { 
        MySubject mySubject = new MySubject();
        MyObserver oba = new MyObserver("oba");
        MyObserver obb = new MyObserver("obb");
        mySubject.addObserver(oba);
        mySubject.addObserver(obb);
        mySubject.setState(18);
    }
}

guava实现方式

首先引包

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>

guava使用的是EventBus事件方式,实现更加的简便

观察者

/** * 观察者 */
public class MyObserver   { 
    //观察者名称
    private String name;

    public MyObserver(String name){ 
        this.name = name;
    }

    // 观察者必须要有一个通知方法
    @Subscribe
    public void update(String str) { 
        // TODO 这里实现业务逻辑
        System.out.println(name + "收到通知:" + str);
    }

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }

}

调用 相当于被观察者为EventBus对象

public class Demo { 

    public static void main(String[] args) { 

        MyObserver oba = new MyObserver("oba");
        MyObserver obb = new MyObserver("obb");
        EventBus eventBus = new EventBus();
        eventBus.register(oba);
        eventBus.register(obb);

        eventBus.post("open");
    }
}

优点:

1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。

缺点:

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

一般应用在需要发布广播的场景,实际业务中更多的是使用mq来实现,源码中使用较多,比如自动注册。

    原文作者:carl的分享笔记
    原文地址: https://blog.csdn.net/aaa31203/article/details/120276247
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。