观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
本质:触发联动。


观察者模式UML类图

java观察者模式升级 观察者模式uml_List


其中Subject是抽象的主题类,也叫做抽象的通知者类。

Observer是抽象的观察者类。

Concrete分别是具体的实现。

比如这样一个情景,公司里老板不在,小王小张小李都在摸鱼,可是老板突然回来了,前台首先发现了老板回来了,那么他需要通知公司的员工停止摸鱼,继续工作。这时前台做的就是具体的通知者类。但是如果前台没来得及通知同事们,老板就已经看到了同事们在摸鱼,这时具体的通知者就是老板自己。

以通知者是老板自己为例,代码如下:

package sjms.observer;

public interface Observer {//抽象的同事类(观察者类)
    public void Update();
}
package sjms.observer;

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

public abstract class Subject {//抽象的通知者类
    private List<Observer> observers = new ArrayList<Observer>();
    //增加观察者
    public void Attach(Observer observer){
        observers.add(observer);
    }
    //移除观察者
    public void Detach(Observer observer){
        observers.remove(observer);
    }
    public void Notify(){
    //使用遍历的方法,对添加进来的同事(观察者)进行通知,并作出相应的状态的改变
        for (Observer observer : observers) {
            observer.Update();
        }
    }
}
package sjms.observer;

public class ConcreteSubject extends Subject{
//具体的通知者类
    private String subjectState;
    //具体被观察者状态

    public String getSubjectState() {
        return subjectState;
    }

    public void setSubjectState(String subjectState) {
        this.subjectState = subjectState;
    }
}
package sjms.observer;

public class ConcreteObserver implements Observer{
//简便期间,只写了一个具体的观察者类(同事类)
    private String name;
    private String observeState;
    private ConcreteSubject subject;

    public ConcreteObserver(ConcreteSubject subject,String name){
        this.subject=subject;
        this.name=name;
    }
    @Override
    public void Update() {
        observeState=subject.getSubjectState();
        //通知被观察者的状态发生了哪种改变, 让相应的观察者作出相应的改变。
        System.out.println(observeState+name+",停止摸鱼,抓紧工作!");
    }

    public ConcreteSubject getSubject() {
        return subject;
    }

    public void setSubject(ConcreteSubject subject) {
        this.subject = subject;
    }
}

package sjms.observer;
//客户端
public class client {
    public static void main(String[] args) {
        ConcreteSubject s = new ConcreteSubject();

        s.Attach(new ConcreteObserver(s,"小王"));
        s.Attach(new ConcreteObserver(s,"小张"));
        s.Attach(new ConcreteObserver(s,"小李"));
        s.setSubjectState("停止摸鱼,抓紧工作!");
        s.Notify();

    }
}

运行结果:

老板我回来了!小王,停止摸鱼,抓紧工作!
老板我回来了!小张,停止摸鱼,抓紧工作!
老板我回来了!小李,停止摸鱼,抓紧工作!

使用观察者模式的动机是什么?
将一个系统分割成一系列相互写作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。

什么时候应该使用观察者模式?

  1. 当一个对象的改变需要同时改变其他对象,而且它不知道具体有多少对象有待改变时,应该考虑观察者模式。比如当电脑打开开机键的时候,电脑的CPU、显示屏、GPU等维持电脑运行的部件都会一起开始运行。
  2. 当一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时使用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
  3. 总的来说,观察者模式所做的工作其实就是在解除耦合。让耦合双方都依赖于抽象,而不是依赖于具体。从而使得各自地变化都不会影响另一边的变化。这就是依赖倒转原则的最佳体现。

特点:
观察者和目标的抽象耦合。
实现了动态联动。
支持广播通信。
但是可能引起无谓操作。

观察者模式还可以使用委托使抽象的观察者和抽象的通知者进行解耦处理,委托可以实现调用不同函数。


一个例子:
有两支股票,在股票发生变化时,分别对购买相应的股票的人进行通知。

UML类图:

java观察者模式升级 观察者模式uml_java_02

package ch10.sjms.invest;

public interface Investor {
    public void Update();
}
package ch10.sjms.invest;

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

public class Stock {
    private List<Investor> investors = new ArrayList<Investor>();
    public void Attach(Investor investor){
        investors.add(investor);
    }
    public void Detach(Investor investor){
        investors.remove(investor);
    }
    public void Notify(){
        for (Investor investor : investors) {
            investor.Update();
        }
    }
}
package ch10.sjms.invest;

public class ConcreteStock extends Stock{
    private String StockState;

    public String getStockState() {
        return StockState;
    }

    public void setStockState(String stockState) {
        StockState = stockState;
    }
}
package ch10.sjms.invest;

public class ConcreteStockB extends Stock{
    private String StockState;

    public String getStockState() {
        return StockState;
    }

    public void setStockState(String stockState) {
        StockState = stockState;
    }
}
package ch10.sjms.invest;

public class ConcreteInvestor implements Investor {
    private String name;
    private String StockState;
    private ConcreteStock stock;
    public ConcreteInvestor(ConcreteStock stock,String name){
        this.stock=stock;
        this.name=name;
    }
    @Override
    public void Update() {
        StockState = stock.getStockState();
        System.out.println("投资者"+name+"的A股票"+StockState);
    }

    public ConcreteStock getStock() {
        return stock;
    }

    public void setStock(ConcreteStock stock) {
        this.stock = stock;
    }
}
package ch10.sjms.invest;

public class ConcreteInvestorB implements Investor {
    private String name;
    private String StockState;
    private ConcreteStockB stock;
    public ConcreteInvestorB(ConcreteStockB stock, String name){
        this.stock=stock;
        this.name=name;
    }
    @Override
    public void Update() {
        StockState = stock.getStockState();
        System.out.println("投资者"+name+"的B股票"+StockState);
    }

    public ConcreteStockB getStock() {
        return stock;
    }

    public void setStock(ConcreteStockB stock) {
        this.stock = stock;
    }
}
package ch10.sjms.invest;

public class client {
    public static void main(String[] args) {
        ConcreteStock s = new ConcreteStock();
        s.Attach(new ConcreteInvestor(s,"张三"));
        s.Attach(new ConcreteInvestor(s,"李四"));

        s.setStockState("涨了");
        s.Notify();

        ConcreteStockB s1=new ConcreteStockB();
        s1.Attach(new ConcreteInvestorB(s1,"王五"));

        s1.setStockState("跌了");
        s1.Notify();
    }
}