简介
观察者形式(Observer Pattern)是一种行为型形式。它界说目标间的一种一对多的依靠关系,当一个目标的状态产生改动时,所有依靠于它的目标都得到告知并被自动更新。
观察者形式运用三个类Subject、Observer和Client。Subject目标带有绑定观察者到Client目标和从Client目标解绑观察者的办法。咱们创立Subject类、Observer笼统类和扩展了笼统类Observer的实体类。
效果
- 一个目标状态更新,其他依靠目标收到告知和自动更新的机制。
- 完成模块化分离,完成主题与观察者交互目标之间的松耦合。 1)观察者界说了目标之间一对多的关系。 2)被观察者(主题)用一个共同的接口来更新观察者。 3)观察者和被观察者用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者完成了观察者接口。
完成步骤
- 创立观察者observer根底接口,包含主题和更新办法
- 创立主题subject笼统类,包含observer列表以及添加和删除办法
- 创立详细的主题类,完成告知办法,发布告知时轮询告知全部观察者
- 创立多个详细观察者,与主题相关,并完成自己的更新办法
- 客户调用时先声明主题,再将观察者分别添加到主题,当主题发布告知时,观察者自动更新
UML
Java代码
观察者接口
// ObserverAPI.java 观察者接口,Java 9已经默许支撑Observer接口
// 这里防止抵触采纳ObserverAPI命名
public interface ObserverAPI {
public Subject subject = null;
public void update(String content);
}
详细观察者
// ConcreteObserver.java 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
// 不同的观察者也能够对应多个主题
public class ConcreteObserver implements ObserverAPI {
public Subject subject;
// 给观察者绑定主题,一起把观察者添加到主题列表
public ConcreteObserver(Subject subject) {
this.subject = subject;
this.subject.register((ObserverAPI) this);
}
// 观察者宣布更新告知,不必独自告知订阅者,由订阅者自行监听
public void update(String content) {
System.out.println(String.format("%s::update() [subject.name = %s content = %s]",
this.getClass().getName(),
this.subject.getName(), content));
}
}
// ConcreteObserver2.java 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
// 不同的观察者能够对应不同的主题。
public class ConcreteObserver2 implements ObserverAPI {
// 这里没有在结构器就绑定某个主题,而是从客户视点去注册观察者
public ConcreteObserver2() {
}
// 观察者宣布更新告知,观察者自行监听
public void update(String content) {
System.out.println(String.format("%s::update() [content = %s]",
this.getClass().getName(), content));
}
}
笼统主题类
// Subject.java 界说笼统主题类或者接口,供详细主题类承继
public abstract class Subject {
private String name;
// protected Set<ObserverAPI> observers = new HashSet<>();
protected List<ObserverAPI> observers = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void register(ObserverAPI observer) {
System.out.println(this.getClass().getName() + "::register() [observer = " + observer.getClass().getSimpleName() + "]");
observers.add(observer);
}
public void remove(ObserverAPI observer) {
observers.remove(observer);
}
// 告知由详细类来完成逻辑
public abstract void notify(String name);
}
详细主题类
// ConcreteSubject.java 观察者主题类,也是发布者,重写详细的告知办法。不同主题能够相关不同的观察者。
public class ConcreteSubject extends Subject {
public ConcreteSubject(String name) {
this.setName(name);
}
// 不同的主题类有自己的告知办法,批量告知绑定的观察者
@Override
public void notify(String content) {
System.out.println(this.getClass().getName() + "::notify() [content = " + content + "]");
for (Object observer : this.observers) {
((ObserverAPI) observer).update(content);
}
}
}
测验调用
/**
* 观察者形式使用十分广泛,主要是观察者提前绑定到发布者
* 当发布者发布音讯时,批量播送告知,而无需逐个告知
* 观察者监听到音讯后自己决议采纳哪一种行为
*/
// 界说一个主题,也便是发布者
Subject concreteSubject = new ConcreteSubject("subject1");
// 再声明观察者,经过结构器注册到主题上
ObserverAPI observer1 = new ConcreteObserver(concreteSubject);
// 也能够独自给主题注册一个新的观察者
concreteSubject.register(new ConcreteObserver2());
// 能够移除观察者目标,能够翻开注释试下
// concreteSubject.remove(observer1);
// 主题开端发布新告知,各观察者自动更新
concreteSubject.notify("hello, this is broadcast.");
Python代码
观察者接口
# ObserverAPI.py 观察者笼统父类,界说一些公共办法
class ObserverAPI:
def __init__(self, name):
self.name = name
# 观察者宣布更新告知,观察者自行监听
def update(self, content):
print(self.__class__.__name__ + '::update() [content = ' + content + ']')
def set_name(self, name):
self.name = name
详细观察者
# ConcreteObserver.py 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
# 不同的观察者也能够对应多个主题
from src.ObserverAPI import ObserverAPI
# 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
# 不同的观察者也能够对应多个主题
class ConcreteObserver(ObserverAPI):
# 给观察者绑定主题,一起把观察者添加到主题列表
def __init__(self, subject, name):
ObserverAPI.__init__(self, name)
# python3支撑的父类调用
# super(ConcreteObserver, self).__init__(name)
# super().__init__(name)
self.subject = subject
subject.register(self)
# 观察者宣布更新告知,不必独自告知订阅者,由订阅者自行监听
def update(self, content):
print(self.__class__.__name__ + '::update() [subject.name = ' +
self.subject.name + ' content = ' + content + ']')
# ConcreteObserver2.py 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
# 不同的观察者能够对应不同的主题。
from src.ObserverAPI import ObserverAPI
# 详细的观察者完成类,也能够当作订阅者,相关对应的主题类。
# 不同的观察者能够对应不同的主题。
class ConcreteObserver2(ObserverAPI):
# 这里没有在结构器就绑定某个主题,而是从客户视点去注册观察者
# 观察者宣布更新告知,观察者自行监听
# def update(self, content):
# print(self.__class__.__name__ + '::update() [content = ' + content +']')
pass
笼统主题类
# Subject.py 界说笼统主题类或者接口,供详细主题类承继
class Subject:
def __init__(self, name):
self.name = name
self.observers = []
def get_name(self):
return self.name
def set_name(self, name):
self.name = name
def register(self, observer):
print(self.__class__.__name__ + '::register() [observer = ' +
observer.__class__.__name__ + ']')
self.observers.append(observer)
def remove(self, observer):
self.observers.remove(observer)
# 告知由详细类来完成逻辑
def notify(self, name):
pass
详细主题类
// ConcreteSubject.py 观察者主题类,也是发布者,重写详细的告知办法。不同主题能够相关不同的观察者。
from src.Subject import Subject
# 观察者主题类,也是发布者,重写详细的告知办法。不同主题能够相关不同的观察者。
class ConcreteSubject(Subject):
# 不同的主题类有自己的告知办法,批量告知绑定的观察者
def notify(self, content):
print(self.__class__.__name__ + '::notify() [content = ' + content +
']')
for observer in self.observers:
observer.update(content)
测验调用
import sys
import os
os_path = os.getcwd()
sys.path.append(os_path)
from src.ConcreteSubject import ConcreteSubject
from src.ConcreteObserver import ConcreteObserver
from src.ConcreteObserver2 import ConcreteObserver2
def test():
'''
* 观察者形式使用十分广泛,主要是观察者提前绑定到发布者
* 当发布者发布音讯时,批量播送告知,而无需逐个告知
* 观察者监听到音讯后自己决议采纳哪一种行为
'''
# 界说一个主题,也便是发布者
concrete_subject = ConcreteSubject('subject1')
# 再声明观察者,经过结构器注册到主题上
observer1 = ConcreteObserver(concrete_subject, 'observer1')
# 也能够独自给主题注册一个新的观察者
observer2 = ConcreteObserver2('observer2')
concrete_subject.register(observer2)
# 能够移除观察者目标
# concrete_subject.remove(observer1)
# 主题开端发布新告知,各观察者自动更新
concrete_subject.notify('hello, this is broadcast.')
if __name__ == '__main__':
print(__file__)
print("test start:")
test()
更多言语版本
不同言语完成设计形式:github.com/microwind/d…