1 基础知识
1.1 标准定义
观察者(Observer)模式标准定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
1.2 分析和说明
观察者(Observer)模式属于对象行为型模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使他们能够自动更新自己。这一模式中主要针对两个对象object和Observer。一个object可以有多个Observer,当—个object对象的状态发生改变时,所有依赖于它的Observer对象都得到通知被自动更新。
观察者(Observer)模式结构如图1所示,其角色包括抽象主题(Subject)角色、抽象观察者(Observer)角色、具体主题(Concrete Subject)角色和具体观察者(Concrete Observer)角色。
图1 观察者模式结构
抽象主题(Subject)角色:主题角色把所有对观察对象的引用保存在此聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,主题角色又叫做抽象被观察者(Observable)角色,一般用一个抽象类或者一个接口实现。
抽象观察者(Observer)角色:为所有具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者角色一般用一个抽象类或者一个接口实现,在这个示意性的实现中,更新接口只包含一个方法(即update()方法),这个方法叫做更新方法。
具体主题(Concrete Subject)角色:将有关状态存主具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)。具体主题角色负责实现对观察者引用的聚集的管理方法。
具体观察者(Concrete Observer)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
2 应用场景举例
比如公司的通讯录是大家都要使用的,同时也是经常变化的。每次通讯录的变化,都要把这些更新后的通讯录发布给所有的公司员工。这就可以采用观察者模式。用例见图2所示。
图2 观察者模式用例图
在这里可以把AbstractAddressBook抽象类理解为抽象主题(Subject)角色。AbstractEmployee抽象类是抽象观察者(Observer)角色。CompanyAddressBook类是具体主题(Concrete Subject)角色。CompanyEmployee类是具体观察者(Concrete Observer)角色。其结构类图如图3所示。CompanyAddressBook类继承AbstractAddressBook抽象类,CompanyEmployee类继承AbstractEmployee抽象类。AbstractEmployee抽象类关联AbstractAddressBook抽象类,即AbstractEmployee类有AbstractAddressBook类的属性。
图3 观察者模式类图
观察者模式实现顺序图见图4,实现顺序描述:
①基于CompanyAddressBook类创建一个addressBook对象;
②基于CompanyEmployee类创建一个employee1对象;
③基于CompanyEmployee类创建一个employee2对象;
④调用addressBook对象的addEmployee方法,把employee1对象作为一个观察者;
⑤调用addressBook对象的addEmployee方法,把employee2对象作为一个观察者;
⑥ addressBook对象发生变化,通知employee1对象和employee2对象这两个观察者。
图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种设计模式(全解析)
(转载自微信公众号:架构设计模式)