设计模式之观察者模式

设计模式之观察者模式

什么是观察者模式

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

角色:

  • 抽象被观察者角色:把所有对观察者对象的引用保存在一个集合中,每个被观察者角色都可以有任意数量的观察者。被观察者提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
    抽象观察者角色:为所有具体的观察者定义一个接口,在得到主题的通知时更新自己。
  • 具体被观察者角色:在被观察者内部状态改变时,给所有登记过的观察者发出通知。具体被观察者角色通常用一个子类实现。
    具体观察者角色:该角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。通常用一个子类实现。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用

观察者模式的场景 — 触发联动(本质)

  1. 当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化
  2. 如果更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变
  3. 当一个对象必须通知其他的对象,但是你又希望这个对象和其他被通知的对象是松散耦合的

怎么使用观察者模式


这里写图片描述


观察者模式的两种实现方式:

推模型

  • 目标对象主动向推送目标的详细消息

拉模型

  • 目标对象通知观察者,值传递少量的信息。如果观察者需要更具体的消息,由观察者主动到目标对象中获取。

  • 一般在这种模型实现中,会把目标对象通过自身update方法传递给观察者


拉模型code:

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

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

    // 将观察者添加集合中
    public void attach(Observer observer) {
        Observers.add(observer);
    }

    // 将观察者重集合中删除。
    public void detach(Observer observer) {
        Observers.remove(observer);
    }

    // 向所有注册者发送消息
    protected void notifyObservers() {
        for (Observer observer : Observers) {
            observer.update(this);
        }
    }
}

/**
 * 观察者接口,定义一个更新的接口,给那些在目标发生改变时被通知的对象
 */
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).getSubjectstate();
        System.out.println("我收到"+observerstate);
    }

}

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

    // 目标对象的状态
    private String subjectstate;

    public String getSubjectstate() {
        return subjectstate;
    }

    public void setSubjectstate(String subjectstate) {
        this.subjectstate = subjectstate;
        // 在保存目标状态时通知。
        this.notifyObservers();
    }

}

public class Client {
    public static void main(String[] args) {
        //创建目标
        ConcreteSubject suj = new ConcreteSubject();
        //创建观察者
        ConcreteObserver obs = new ConcreteObserver();
        //注册观察者
        suj.attach(obs);
        //发布信息
        suj.setSubjectstate("有新消息");
    }

}

拉模型code:

/**
 * 具体的观察者对象,实现更新方法,使自身和目标的状态一致
 */
public class ConcreteObserver implements Observer {
    @Override
    public void update(String content) {
        System.out.println("我收到"+content);
    }
}

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

    // 目标对象的状态
    private String subjectstate;

    public String getSubjectstate() {
        return subjectstate;
    }

    public void setSubjectstate(String subjectstate) {
        this.subjectstate = subjectstate;
        // 在保存目标状态时通知。
        this.notifyObservers(subjectstate);
    }

}

/**
 * 观察者接口,定义一个更新的接口,给那些在目标发生改变时被通知的对象
 */
public interface Observer {
    // 传入目标对象,方便获取目标对象的状态。
    public void update(String content);

}


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

    // 将观察者添加集合中
    public void attach(Observer observer) {
        Observers.add(observer);
    }

    // 将观察者重集合中删除。
    public void detach(Observer observer) {
        Observers.remove(observer);
    }

    // 向所有注册者发送消息
    protected void notifyObservers(String content) {
        for (Observer observer : Observers) {
            observer.update(content);
        }
    }
}

认识观察者模式

  1. 目标与之间的关系

    • 一对一,多对一的关系,为不同的观察者设置不同的回掉方法。
  2. 单项依赖

    • 观察者等待目标通知,观察者始终是被动的
  3. 命令建议

    • 观察者模式又被称为发布订阅模式
    • 目标接口的,建议在后面加上subject作为标识
    • 观察者接口定义,建议在Observer作为标识
    • 观察者接口的更新方法,建议名称为update
  4. 触发通知的时间

    • 先添加后通知
  5. 观察者模式顺序示意图

    • 准备阶段
    • 运行阶段
      这里写图片描述
  6. 通知的的顺序

    • 通知的的顺序是平行的

比较

  • 推模型是假定目标对象知道观察者需要的数据。
  • 拉模型是目标对象不知道观察者需要的具体数据,把自身传给观察者,有观察者来取

java观察者模式的应用:

  1. 不需要再定义观察者和目标接口(JDK已经定义)。
  2. 具体的目标实现里面不需要再维护观察者的注册信息,Java中的Observable类里面已经实现。
  3. 触发通知的方式有一点变化,要先调用setChanged方法,这个是Java为了帮助实现更精确的触发控制而提供的功能。
  4. 具体观察者的实现里面,update方法其实能同时支持推模型和拉模型,这个Java在定义的时候,已经考虑。
import java.util.Observable;
import java.util.Observer;

public class ConcreteObserver implements Observer{
    @Override
    public void update(Observable o, Object arg) {
//      System.out.println("收到了推送过来的"+arg);

        System.out.println("收到了消息,拉取目标对象的消息"+((Subject)o).getContent());
    }
}

import java.util.Observable;

public class Subject extends Observable{

    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
        //在通知之前,在java中使用Observer模式时必须调用setChanged();
        this.setChanged();
        //通知--推模型
        //notifyObservers(content);
        //通知 --拉模型
        notifyObservers();
    }
}

public class Client {
    public static void main(String[] args) {
        //创建目标
        Subject suj = new Subject();
        //创建观察者
        ConcreteObserver obs = new ConcreteObserver();
        //注册观察者
        suj.addObserver(obs);
        //发布信息
        suj.setContent("天气不好");
    }

}

为什么要用观察者模式

观察者的优点:

  • 观察者模式实现了观察者和目标之间的抽象耦合
  • 观察者模式实现了动态联动
  • 观察者模式支持广播通信

缺点:

  • 可能引起无谓的操作

观察者模式的衍生:

区别对待观察者模式
对不同的消息通知不同的观察者,将subject类的notifyObservers()方法改为abstract具体在子类中进行判断实现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值