行为型 观察者模式

2020/05/24

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。

参与者有:

  1. 被观察者(Subject):知道它的通知对象,事件发生后会通知所有它知道的对象,提供添加删除观察者的接口。
  2. 观察者(Observer):提供通知后的更新事件
  3. 具体被观察者(ConcreteSubject):被观察者具体的实例,存储观察者感兴趣的状态。
  4. 具体观察者(ConcreteObserver):观察者的具体实现。

在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如说邮件系统,你在收到一封邮件的时候经常桌面上会有通知,告诉你有邮件收到了。再比如,我们要设计一个自动部署的功能,就像eclipse开发时,只要修改了文件,eclipse就会自动将修改的文件部署到服务器中。 观察者模式有个特点:那就是一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。

用 Java 代码表示:

被观察者类:

import java.util.ArrayList;

abstract class Subject {
    private ArrayList<Observer> observers;
    public Subject() {
	observers = new ArrayList<>();
    }
    public void attach(Observer observer) {
 	observers.add(observer);
    }
    public void detach(Observer observer) {
	observers.remove(observer);
    }
    public void notifyObserver(int state) {
	for(Observer o: observers) {
            o.update(state);
	}
    }
}

class ConcreteSubject extends Subject {
    private int subjectState;
    public int getState() {
	return subjectState;
    }
    public void setState(int newState) {
	subjectState = newState;
	System.out.println("subject' state change to " + newState);
	this.notifyObserver(subjectState);
    }
}

观察者类:

interface Observer {
    public void update(int state);
}

class ConcreteObserver1 implements Observer {
    public void update(int state) {
	System.out.println("ConcreteObserver1 know state had changed to " + state);
	doSomething();
    }	
    private void doSomething() {
	System.out.println("ConcreteObserver1 do something!!!");
    }
}

class ConcreteObserver2 implements Observer {
    public void update(int state) {
	System.out.println("ConcreteObserver2 know state had changed to " + state);
	doSomething();
    }	
    private void doSomething() {
	System.out.println("ConcreteObserver2 do something!!!");
    }
}

class ConcreteObserver3 implements Observer {
    public void update(int state) {
	System.out.println("ConcreteObserver3 know state had changed to " + state);
	doSomething();
    }	
    private void doSomething() {
	System.out.println("ConcreteObserver3 do something!!!");
    }
}

客户端调用:

class Client {
    public static void main(String[] args) {
	ConcreteSubject subject = new ConcreteSubject();	
	Observer o1 = new ConcreteObserver1();
	Observer o2 = new ConcreteObserver2();
	Observer o3 = new ConcreteObserver3();
		
	subject.attach(o1);
	subject.attach(o2);
	subject.attach(o3);

	subject.setState(11);
	subject.detach(o2);

	subject.setState(12);
    }
}

运行结果:

img

观察者模式不难,即一个对象的变化会通知其他对象,其他对象对其改变作出响应的处理。

观察者模式适用于:

  1. 当一个对象在不知道对方具体是如何实现时需要通知其它对象
  2. 当一个对象改变需要通知不确定数的对象时

观察者模式的优点:

观察者与被观察者之间是属于轻度的关联关系,并且是抽象耦合的,这样,对于两者来说都比较容易进行扩展。

观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。并且,在链式结构中,比较容易出现循环引用的错误,造成系统假死。

考虑下面这样的场景:你被要求开发一个简单的股票监控应用程序。初始要求是:

  1. 股票有一个符号名称和当前价格。
  2. 投资者可以监控它的当前价值股票。
  3. 当股票价格变化时,所有监测的股票投资者都被告知变化。

根据上面的例子,很容易可以写出以下的代码:

股票类:

import java.util.Vector;

abstract class Stock{
    private Vector<Investor> investors = new Vector<Investor>();
    protected int price = 0;
    public void addInvestor(Investor i){
  	this.investors.add(i);
    }
    public void delInvestor(Investor i){
	this.investors.remove(i);
    }
    protected void notifyInvestors(int price){
	System.out.println("begin to notify the investors.");
	for(Investor i:investors){
            i.update(price);
	}
    };
    public abstract void setPrice(int price);
}

class TxStock extends Stock{
    public void setPrice(int price){
	System.out.println("change price.");
	this.price = price;
	this.notifyInvestors(price);
    }
}

投资者类:

interface Investor{
    public void update(int price);
}

class BeijingInvestor implements Investor{
    private String name;
    public BeijingInvestor(String name){
	this.name = name;
    }
    public void update(int price){
	System.out.println("Beijing Investor " + this.getName() + " know the stock change to " + price);
    }
    public String getName(){
 	return this.name;
    }
}

class ShenyangInvestor implements Investor{
    private String name;
    public ShenyangInvestor(String name){
	this.name = name;
    }
    public void update(int price){
	System.out.println("Shenyang Investor " + this.getName() + " know the stock change to " + price);
    }
    public String getName(){
	return name;
    }
}

客户端调用:

class Client{
    public static void main(String[] args){
	Stock stock = new TxStock();
	stock.addInvestor(new BeijingInvestor("Lindz"));
	stock.addInvestor(new ShenyangInvestor("Xun"));
	stock.setPrice(19);
	stock.setPrice(25);
    }
}

运行结果:

img

作者:林东洲 链接:https://zhuanlan.zhihu.com/p/25045567 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

观察者模式 菜鸟教程

Post Directory