【笔记整理】图解设计模式 | 第17章 Observer模式(发送状态变化通知)

【笔记整理】图解设计模式 | 导航


定义

  • 当观察对象的状态发生变化时,会通知给观察者。
  • Observer模式适用于根据对象状态进行相应处理的场景。

Observer模式中的登场角色

  • Subject(观察对象)

       Subject角色表示观察对象。Subject角色定义了注册观察者和删除观察者的方法。此外,它还声明了“获取现在的状态”的方法。

  • ConcreteSubject(具体的观察对象)

       ConcreteSubject角色表示具体的被观察对象。当自身状态发生变化后,它会通知所有已经注册的Observer角色。

  • Observer(观察者)

       Observer角色负责接收来自Subject角色的状态变化的通知。为此,它声明了update方法。

  • ConcreteObserver(具体的观察者)

       ConcreteObserver角色表示具体的Observer。当它的update方法被调用后,会去获取要观察的对象的最新状态。


Observer模式的类图


拓展思路的要点

  • 这里也出现了可替换性

       在Observer模式中,有带状态的ConcreteSubject角色和接收状态变化通知的ConcreteObserver角色。连接这两个角色的就是它们的接口(API)Subject角色和Observer角色。

       利用抽象类和接口从具体类中抽出抽象方法。

       在将实例作为参数传递至类中,或者在类的字段中保存实例时,不使用具体类型,而是使用抽象类型和接口。

  • Observer的顺序

       Subject角色中注册有多个Observer角色。

       通常,在设计ConcreteObserver角色的类时,需要注意这些Observer的update方法的调用顺序,不能应为update方法的调用顺序发生改变而产生问题。通常,只要保持各个类的独立性,就不会发生类的依赖关系混乱的问题。

  • 当Observer的行为会对Subject产生影响时

       注意死循环问题。

  • 传递更新信息的方式
void update(Subject subject);              ......(1)
void update(Subject subject, int number);  ......(2)
void update(int number);                   ......(3)

       (1)只传递了Subject角色作为参数。Observer角色可以从Subject角色中获取数据。

       (2)除了传递Subject角色以外,还传递了Observer所需的数据。这样就省去了Observer自己获取数据的麻烦。不过,Subject角色就知道了Observer所要进行的处理的内容了。

       (3)比(2)简单,省略了Subject角色。如果一个Observer角色需要观察多个Subject角色的时候,此方法就不适用了。

  • 从“观察”变为“通知”

       Observer本来的意思是“观察者”,但实际上Observer角色并非主动地去观察,而是被动地接收来自Subject角色的通知。因此Observer模式也被称为Publish-Subscribe(发布-订阅)模式。


延伸阅读:java.util.Observer接口

Java类库中的java.util.Observer接口和java.util.Observable类就是一种Observer模式。但是并不好用,原因Java只能单一继承。


相关的设计模式

       在Mediator模式中,有时会使用Observer模式来实现Mediator角色与Colleague角色之间的通信。

       就“发送状态变化通知”这一点而言,Mediator模式与Observer模式是类似的。不过,两种模式中,通知的目的和视角不同。

       在Mediator模式中,虽然也会发送通知,不过那不过是为了对Colleague角色进行仲裁而已。

       而在Observer模式中,将Subject角色的状态变化通知给Observer角色的目的则主要是为了使Subject角色和Observer角色同步。


代码

  • Subject(观察对象)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public abstract class NumberGenerator {

	private List<Observer> observers = new ArrayList<Observer>(); // 保存Observer们

	public void addObServer(Observer observer) { // 注册Observer
		observers.add(observer);
	}

	public void deleteObserver(Observer observer) { // 删除Observer
		observers.remove(observer);
	}

	public void nodifyObservers() { // 向Observer发送通知
		Iterator<Observer> it = observers.iterator();
		while (it.hasNext()) {
			Observer o = it.next();
			o.update(this);
		}
	}

	public abstract int getNumber(); // 获取数值

	public abstract void execute(); // 生成数值
}
  • ConcreteSubject(具体的观察对象)
import java.util.Random;

public class RandomNumberGenerator extends NumberGenerator {

	private Random random = new Random(); // 随机数生成器
	private int number; // 当前数值

	@Override
	public int getNumber() { // 获取当前数值
		return number;
	}

	@Override
	public void execute() {
		for (int i = 0; i < 20; i++) {
			number = random.nextInt(50);
			nodifyObservers();
		}
	}

}
  • Observer(观察者)
public interface Observer {

	void update(NumberGenerator generator);
}
  • ConcreteObserver(具体的观察者)
public class DigitObserver implements Observer {

	@Override
	public void update(NumberGenerator generator) {
		System.out.println("DigitObserver:" + generator.getNumber());
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
public class GraphObserver implements Observer {

	@Override
	public void update(NumberGenerator generator) {
		System.out.print("GraphObserver:");
		int count = generator.getNumber();
		for (int i = 0; i < count; i++) {
			System.out.print("*");
		}
		System.out.println("");
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}
  • Main
public class Main {

	public static void main(String[] args) {
		NumberGenerator generator = new RandomNumberGenerator();
		Observer observer1 = new DigitObserver();
		Observer observer2 = new GraphObserver();
		generator.addObServer(observer1);
		generator.addObServer(observer2);
		generator.execute();
	}

}

注:博客中的图片来自网上。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值