《设计模式》-- 观察者模式

来源:互联网 发布:卓睿安位软件 编辑:程序博客网 时间:2024/06/14 18:32

观察者模式

参考:《JAVA与模式》之观察者模式

  • 观察者模式
    • 认识
    • 思考
    • 使用场景
    • 优缺点
    • UML图
    • 代码实现
      • 推模型
      • 拉模型
      • jdk提供的接口

认识

观察者模式是对象的行为模式,定义了一种一对多的依赖关系,多个观察者对象同时监听一个主题对象,当主题对象状态发生改变时,会通知所有观察者对象更新。是一种发布-订阅模式。

思考

在观察者模式中,观察者和目标是单向依赖的,只有观察者依赖目标,观察者只能被动的去等到目标的通知,等待目标传值给它。

  • 推模型是假定目标知道观察者需要的数据;而拉模型是目标不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。
  • 推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是目标对象本身,观察者可以获取目标对象上的任何非私有属性。

实质:触发联动

使用场景

  1. 当一个对象的改变需要通知其他对象时选用观察者模式
  2. 当一个抽象模型有两个方面,一个方面的操作依赖另一个方面的状态变化时选用观察者模式

优缺点

  • 优点

    1. 实现了观察者和目标之间的解耦合
    2. 支持广播通知
  • 缺点

UML图

定义一个目标抽象类,在抽象类中维护一个观察者的list,通过准备阶段创建观察者add到list中,提供添加和删除观察者的方法,提供通知观察者的方法。

定义一个目标具体实现类,在该实现类中如果发生变化调用notifyObserves通知所有观察者

定义一个观察者接口和一系列观察者实现类对象,提供方法供目标回调

image

●  目标(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,提供目标更新时通知观察者的方法。

  ●  目标实现(ConcreteSubject)角色:具体目标实现,用来维护目标状态,当目标状态发生改变时通知已注册的所有观察者。

  ●  抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,定义目标对象通知观察者时的回调方法。

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者接收通知进行后续处理。

  • 准备阶段

image

  • 运行阶段

image

代码实现

推模型

目标回调观察者时传入具体的值

//目标抽象类public abstract class Subject {    // 注册的观察者列表    private List<Observer> observerList = new ArrayList<Observer>();    // 注册观察者    public void attach(Observer observer) {        observerList.add(observer);    }    // 移除观察者    public void detach(Observer observer) {        observerList.remove(observer);    }    // 定义通知方法    protected void nodifyObservers(String newState) {        for(Observer observer:observerList){            observer.update(newState);        }    }}//目标具体实现类public class ConcreteSubject extends Subject {    private String state;    public String getState() {        return state;    }    //目标更新时通知所有观察者    public void change(String newState) {        state = newState;        System.out.println("主题状态为:" + state);        // 状态发生改变,通知各个观察者        this.nodifyObservers(state);    }}//观察者接口public interface Observer {    //提供方法供目标回调通知并传入值    public void update(String state);}//观察者具体实现类public class ConcreteObserver implements Observer {    //观察者的状态    private String observerState;    //通过目标回调获取目标传递给回来的值    public void update(String state) {        /**         * 更新观察者的状态,使其与目标的状态保持一致         */        observerState = state;        System.out.println("状态为:"+observerState);    }}//客户端调用public class Client {    public static void main(String[] args) {        //创建目标        ConcreteSubject subject = new ConcreteSubject();        //创建观察者        Observer observer1 = new ConcreteObserver();        Observer observer2 = new ConcreteObserver();        //注册观察者        subject.attach(observer1);        subject.attach(observer2);        //更新目标并通知所有观察者        subject.change("new");        subject.detach(observer2);        subject.change("again");    }}

拉模型

目标回调观察者时将目标对象传递给观察者

//目标抽象类public abstract class Subject {    // 注册的观察者列表    private List<Observer> observerList = new ArrayList<Observer>();    // 注册观察者    public void attach(Observer observer) {        observerList.add(observer);    }    // 移除观察者    public void detach(Observer observer) {        observerList.remove(observer);    }    // 定义通知方法,直接将目标对象回调传递给观察者    protected void nodifyObservers() {        for(Observer observer:observerList){            observer.update(this);        }    }}//目标具体实现类public class ConcreteSubject extends Subject {    private String state;    public String getState() {        return state;    }    //目标更新时通知所有观察者    public void change(String newState) {        state = newState;        System.out.println("主题状态为:" + state);        //将目标对象通过回调传递给每个观察者        this.nodifyObservers();    }}//观察者接口public interface Observer {    //提供方法供目标回调通知并传入值    public void update(Subject subject);}//观察者具体实现类public class ConcreteObserver implements Observer {    //观察者的状态    private String observerState;    //通过目标回调获取目标对象    @Override    public void update(Subject subject) {        //通过目标对象的引用获取目标对象中的值        observerState = ((ConcreteSubject)subject).getState();        System.out.println("状态为:"+observerState);    }}//客户端调用public class Client {    public static void main(String[] args) {        //创建目标        ConcreteSubject subject = new ConcreteSubject();        //创建观察者        Observer observer1 = new ConcreteObserver();        Observer observer2 = new ConcreteObserver();        //注册观察者        subject.attach(observer1);        subject.attach(observer2);        //更新目标并通知所有观察者        subject.change("new");        subject.detach(observer2);        subject.change("again");    }}

jdk提供的接口

//目标对象继承Observable接口public class Watched extends Observable接口{    private String data = "";    public String getData() {        return data;    }    public void setData(String data) {        if(!this.data.equals(data)){            this.data = data;            setChanged();        }        notifyObservers();    }}//观察者实现Observer接口public class Watcher implements Observer{    public Watcher(Observable o){        o.addObserver(this);    }    @Override    public void update(Observable o, Object arg) {          System.out.println("状态发生改变:" + ((Watched)o).getData());    }}public class Client {    public static void main(String[] args) {         //创建被观察者对象        Watched watched = new Watched();        //创建观察者对象,并将被观察者对象登记        Observer watcher = new Watcher(watched);        //给被观察者状态赋值        watched.setData("start");        watched.setData("run");        watched.setData("stop");    }}
0 0
原创粉丝点击