【设计模式 - 19】之观察者模式(Observer)

1      模式简介

观察者模式的介绍:

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象的状态发生改变时,它的所有依赖者都会收到通知并自动更新。

 

发布者(被观察者) + 订阅者(观察者) = 观察者模式

 

观察者模式的优点:

1)        观察者和被观察者是抽象耦合的;

2)        观察者模式建立了一套触发机制(触发联动)。

 

观察者模式的缺点:

1)        如果一个被观察者有很多直接或简介的观察者的话,将所有的观察者都通知到会花费很多时间;

2)        如果在观察者和被观察者之间有循环依赖的话,被观察者会触发它们之间的的循环调用,可能会导致系统崩溃(因此,在观察者模式中应该避免观察者和被观察者之间的循环调用)。

 

观察者模式的适用场景:

1)        当需要完成“触发联动”的功能时,即当一个对象的状态发生变化时,会触发与之相关联的多个对象状态的改变;

2)        当观察者对象不需要知道主题对象(被观察者)的实现细节时。

 

观察者模式的UML图:

 

2      案例

在这个案例中,我们模拟报社的职能:

1)        报社的业务就是出版报纸;

2)        向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,就会一直收到新报纸;

3)        当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来;

4)        只要报社还在运营,就会一直有人向他们订阅或取消订阅报纸。

 

2.1    手写观察者模式

手写的观察者模式的代码如下:

被观察者的抽象父类Subject代码如下:

public abstract class Subject {
	protected String name;
	protected Object thing;

	abstract void addObserver(Observer observer);

	abstract void removeObserver(Observer observer);

	abstract void notifyObservers();

	public void setThing(Object thing) {
		this.thing = thing;
		System.out.println(this.name + "发布了一条消息:" + thing.toString());
		notifyObservers();
	}
}
被观察者的具体类:报社类NewsOffice中的代码:

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

public class NewsOffice extends Subject {
	private List<Observer> observers;

	public NewsOffice() {
		super.name = "报社";
		this.observers = new ArrayList<Observer>();
	}

	@Override
	public void addObserver(Observer observer) {
		this.observers.add(observer);
	}

	@Override
	public void removeObserver(Observer observer) {
		int index = this.observers.indexOf(observer);
		if (index >= 0) {
			this.observers.remove(observer);
		}
	}

	@Override
	void notifyObservers() {
		if (this.observers.size() > 0) {
			for (Observer observer : this.observers) {
				observer.update(super.thing);
				observer.display();
			}
		}
	}
}
观察者的抽象父类Observer中的代码:

public abstract class Observer {
	protected String name;
	protected Object thing;

	public void update(Object thing) {
		this.thing = thing;
		System.out.println(this.name + "收到了消息:" + thing.toString());
	}

	public abstract void display();
}
具体的观察者Person1中的代码:

public class Person1 extends Observer {

	public Person1() {
		super.name = "Person1";
	}

	@Override
	public void display() {
		System.out.println(super.name + "一边听歌一边看报纸");
	}
}
具体的观察者还有Person2和Company1,这里以Person1为例,有需要的朋友可以通过博客最后的GitHub地址去GitHub上下载。

测试类Test中的代码:

public class Test {
	public static void main(String[] args) {
		// 创建主题(被观察者)
		Subject office = new NewsOffice();
		// 创建观察者
		Observer person1 = new Person1();
		Observer person2 = new Person2();
		Observer company1 = new Compony1();
		// 为观察者注册主题
		office.addObserver(person1);
		office.addObserver(person2);
		office.addObserver(company1);

		// 主题发送消息
		office.setThing("第一条新闻");
		System.out.println();
		office.setThing("哈哈哈哈哈哈哈哈哈哈");
	}
}
运行结果如下图所示:



2.2    JAVA内置观察者模式

JAVA内置的观察者模式的代码如下:

被观察者报社类NewsOffice(继承了JAVA内置的被观察者Observable类)的代码如下:

public class NewsOffice extends Observable {

	public void setNews(String news) {
		System.out.println("报社发布了新闻:" + news);
		super.setChanged();
		super.notifyObservers(news);
	}
}
自定义的观察者CustomObserver(实现了JAVA内置的观察者接口Observer和自定义的展示接口IDisplay)的代码如下:

// 自定义的展示接口IDisplay中的代码:
public interface IDisplay {
	void display();
}


// 自定义的观察者CustomObserver中的代码:
public abstract class CustomObserver implements Observer, IDisplay {
	protected String name;

	@Override
	public void update(Observable subject, Object thing) {
		System.out.println(this.name + "收到了消息:" + thing.toString());
	}
}
具体观察者Person1中的代码:

public class Person1 extends CustomObserver {

	public Person1() {
		super.name = "Person1";
	}

	@Override
	public void display() {
		System.out.println(super.name + "一边听歌一边看报纸");
	}
}
Person2和Company1中的代码同样在GitHub中。

测试类Test中的代码:

public class Test {
	public static void main(String[] args) {
		// 创建主题(被观察者)
		NewsOffice office = new NewsOffice();
		// 创建三个观察者
		CustomObserver person1 = new Person1();
		CustomObserver person2 = new Person2();
		CustomObserver company1 = new Company1();
		// 为观察者注册主题
		office.addObserver(person1);
		office.addObserver(person2);
		office.addObserver(company1);

		// 被观察者发布消息
		office.setNews("哈哈哈哈哈哈");
		System.out.println();
		office.setNews("这不是一条垃圾新闻");
	}
}
运行结果如下图所示:



最后贴出观察者模式的GitHub代码地址:【GitHub - Observer】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值