Gof23种设计模式(20)——观察者模式(Observer)

2020年8月14日10:24:34 评论 73

1 基础知识

1.1 标准定义

观察者(Observer)模式标准定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

1.2 分析和说明

观察者(Observer)模式属于对象行为型模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。这一模式中主要针对两个对象object和Observer。一个object可以有多个Observer,当—个object对象的状态发生改变时,所有依赖于它的Observer对象都得到通知被自动更新。

观察者(Observer)模式结构如图1所示,其角色包括抽象主题(Subject)角色、抽象观察者(Observer)角色、具体主题(Concrete Subject)角色和具体观察者(Concrete Observer)角色。

Gof23种设计模式(20)——观察者模式(Observer)图1 观察者模式结构

 抽象主题(Subject)角色:主题角色把所有对观察对象的引用保存在此聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。

 抽象观察者(Observer)角色:为所有具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现,在这个示意性的实现中,更新接口只包含一个方法(即update()方法),这个方法叫做更新方法。

 具体主题(Concrete Subject)角色:将有关状态存主具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色负责实现对观察者引用的聚集的管理方法。

 具体观察者(Concrete Observer)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

2 应用场景举例

比如公司的通讯录是大家都要使用的,同时也是经常变化的。每次通讯录的变化,都要把这些更新后的通讯录发布给所有的公司员工。这就可以采用观察者模式。用例见图2所示。

Gof23种设计模式(20)——观察者模式(Observer)

图2 观察者模式用例图

在这里可以把AbstractAddressBook抽象类理解为抽象主题(Subject)角色。AbstractEmployee抽象类是抽象观察者(Observer)角色。CompanyAddressBook类是具体主题(Concrete Subject)角色。CompanyEmployee类是具体观察者(Concrete Observer)角色。其结构类图如图3所示。CompanyAddressBook类继承AbstractAddressBook抽象类,CompanyEmployee类继承AbstractEmployee抽象类。AbstractEmployee抽象类关联AbstractAddressBook抽象类,即AbstractEmployee类有AbstractAddressBook类的属性。

Gof23种设计模式(20)——观察者模式(Observer)图3 观察者模式类图

观察者模式实现顺序图见图4,实现顺序描述:
①基于CompanyAddressBook类创建一个addressBook对象;
②基于CompanyEmployee类创建一个employee1对象;
③基于CompanyEmployee类创建一个employee2对象;
④调用addressBook对象的addEmployee方法,把employee1对象作为一个观察者;
⑤调用addressBook对象的addEmployee方法,把employee2对象作为一个观察者;
⑥ addressBook对象发生变化,通知employee1对象和employee2对象这两个观察者。

Gof23种设计模式(20)——观察者模式(Observer)

图4 观察者模式实现顺序图

3.Java的实现程序代码

Java程序实现主要包括AbstractAddressBook抽象类文件,AbstractEmployee抽象类文件,CompanyAddressBook类文件和CompanyEmployee类文件等4个文件。其关系如图3所示。下面分别列出这4个文件的程序代码,最后列出测试代码并显示输出结果。

AbstractAddressBook抽象类程序代码清单01所示。

程序代码清单01

public abstract class AbstractAddressBook {

	protected List<AbstractEmployee> employeeList = new ArrayList<AbstractEmployee>();
	protected String addressBook;

	public String getAddressBook() {
		return addressBook;
	}

	public void setAddressBook(String addressBook) {
		this.addressBook = addressBook;
	}

	public void addEmployee(AbstractEmployee employee) {
		employeeList.add(employee);
	}

	public void removeEmployee(AbstractEmployee employee) {
		employeeList.remove(employee);
	}

	public void notice() {
	}
}

AbstractEmployee抽象类程序代码清单02所示。

程序代码清单02

public abstract class AbstractEmployee {

	protected AbstractAddressBook addressBook;
	protected String addressBookContents;

	public AbstractAddressBook getAddressBook() {
		return addressBook;
	}

	public void setAddressBook(AbstractAddressBook addressBook) {
		this.addressBook = addressBook;
	}

	public void update(AbstractAddressBook book) {
		setAddressBook(book);
		addressBookContents = addressBook.getAddressBook();
	}
}

CompanyAddressBook继承AbstractAddressBook抽象类,其程序代码清单03所示。

程序代码清单03

public class CompanyAddressBook extends AbstractAddressBook {

	public CompanyAddressBook() {
		addressBook = "旧的通信录";
	}

	public void addEmployee(AbstractEmployee employee) {

		// employee.setAddressBook(this);
		employee.update(this);
		super.addEmployee(employee);
	}

	public void notice() {
		for (int i = 0; i < employeeList.size(); i++) {
			employeeList.get(i).update(this);
		}
	}
}

CompanyEmployee继承AbstractEmployee抽象类,其程序代码清单04所示。

程序代码清单04

public class CompanyEmployee extends AbstractEmployee {

	private String employeeName;

	public String getEmployeeName() {
		return employeeName;
	}

	public void setEmployeeName(String employeeName) {
		this.employeeName = employeeName;
	}

	public CompanyEmployee(String employeeName) {
		super();
		this.employeeName = employeeName;
	}

	public void update(AbstractAddressBook book) {
		super.update(book);
		System.out.println(getEmployeeName() 
				+ "更新通讯录。" + "通讯录内容:" + addressBookContents);
	}
}

观察者模式测试程序的代码清单05如下:

程序代码清单05

public class Client {

	public static void main(String[] args) {

		System.out.println("——————原有的通讯录——————");
		AbstractAddressBook addressBook = new CompanyAddressBook();
		AbstractEmployee employee1 = new CompanyEmployee("employee1");
		AbstractEmployee employee2 = new CompanyEmployee("employee2");

		addressBook.addEmployee(employee1);
		addressBook.addEmployee(employee2);

		System.out.println("——————更新的通讯录——————");
		
		String newAddressBook = "新的通讯录";
		addressBook.setAddressBook(newAddressBook);
		addressBook.notice();
	}
}

观察者模式测试类输出结果如下所示:

——————原有的通讯录——————
employee1更新通讯录。通讯录内容:旧的通信录
employee2更新通讯录。通讯录内容:旧的通信录
——————更新的通讯录——————
employee1更新通讯录。通讯录内容:新的通讯录
employee2更新通讯录。通讯录内容:新的通讯录

4 扩展和说明

在java语言中已经实现了Observer设计模式。JDK里提供的Observer设计模式的实现由java.util.Observable类和java.util.Observer接口组成。java.util.Observer是观察者角色,java.util.Observable是被观察目标角色,对应于Subject角色。

Observer是一个接口,它里面只定义了一个方法:public void update(Observable obs,Object obj)在用户实现的这个方法中,可以只对obs的某些事件进行响应,也可以通过调用getXXX()来得到obs最新的状态。上述例子的java程序可以由Employee类、AddressBook类、Client类等三个文件实现。

AddressBook类源程序见程序清单08。

程序代码清单08

import java.util.Observable;

public class AddressBook extends Observable {

	protected String addressBookContent;

	public AddressBook() {
		super();
	}

	public String getAddressBook() {
		return addressBookContent;
	}

	public void setAddressBook(String addressBook) {
		this.addressBookContent = addressBook;
	}

	public void addEmployee(Employee employee) {
		super.addObserver(employee);
	}

	public void removeEmployee(Employee employee) {
		deleteObserver(employee);
	}

	public void modifyAddress(String addressBook) {
		setAddressBook(addressBook);
		setChanged();
		notifyObservers(addressBook);
	}
}

Employee.类源程序见程序清单09。

程序代码清单08

import java.util.Observable;
import java.util.Observer;

public class Employee implements Observer {

	protected String addressBookContents;
	private String employeeName;

	public Employee(String employeeName) {
		setEmployeeName(employeeName);
	}

	public String getEmployeeName() {
		return employeeName;
	}

	public void setEmployeeName(String employeeName) {
		this.employeeName = employeeName;
	}

	public String getAddressBookContents() {
		return addressBookContents;
	}

	public void setAddressBookContents(String addressBookContents) {
		this.addressBookContents = addressBookContents;
	}

	public void update(Observable object, Object arg) {
		if (arg instanceof String) {
			setAddressBookContents(arg.toString());
			System.out.println(getEmployeeName() 
					+ "获得通信录:" + getAddressBookContents());
		}
	}
}

Client类源程序见程序清单10。

程序代码清单10

public class Client {

	public static void main(String[] args) {

		System.out.println("——————原有的通讯录——————");

		AddressBook addressBook = new AddressBook();
		
		Employee employee1 = new Employee("employee1");
		Employee employee2 = new Employee("employee2");
		Employee employee3 = new Employee("employee3");

		addressBook.addEmployee(employee1);
		addressBook.addEmployee(employee2);
		addressBook.addEmployee(employee3);
		addressBook.modifyAddress("旧的通讯录");

		System.out.println("——————更新的通讯录——————");

		String newAddressBook = "新的通讯录";
		addressBook.modifyAddress(newAddressBook);
	}
}

参考链接

11种行为型模式

Gof23种设计模式(13)——解释器模式(Interpreter)
Gof23种设计模式(14)——模板方法模式(Template Method)
Gof23种设计模式(15)——责任链模式(Chain of Responsibility)
Gof23种设计模式(16)——命令模式(Command)
Gof23种设计模式(17)——迭代器模式(Iterator)
Gof23种设计模式(18)——中介者模式(Mediator)
Gof23种设计模式(19)——备忘录模式(Memento)
Gof23种设计模式(20)——观察者模式(Observer)
Gof23种设计模式(21)——状态模式(State)
Gof23种设计模式(22)——策略模式(Strategy)
Gof23种设计模式(23)——访问者模式(Visitor)
Gof23种设计模式 —— 行为型模式总结和比较

回到总目录Gof23种设计模式(全解析)

(转载自微信公众号:架构设计模式)

素课网
  • 本文由 发表于 2020年8月14日10:24:34
  • 转载请注明:https://www.suketech.com/9284.html
设计模式:面向对象设计的六大原则 - 总结 设计模式

设计模式:面向对象设计的六大原则 – 总结

开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: