设计模式中的观察者模式是我感到比较迷惑的一种模式,刚开始接触的时候看的不太懂,因为当时在学Qt,而Qt的信号与槽的机制就有点类似于观察者模式,但是Qt却不能完全体现,以至于我在这两者之间感到有些困惑,直到后来看了《大话设计模式》后有点了解——我真的是太喜欢这本书了,后来无意中看到这篇观察者模式文章
感觉有点大彻大悟的感觉,虽然我学的是python,而博主用的是Java写的,但我认为语言其实并不是我们学习的一个难点,设计的原则与模式才是精髓,它凌驾于语言之上,是一种思想,能跨越语言之间的障碍,这里的java代码是引用了以上博主的代码,在这里我用Python复现一下吧,关于观察者模式的具体思想可以参考以上博主的文章。
Java代码实现
抽象主题(Subject)角色
public class Subject {
//观察者数组
private Vector<Observer> oVector = new Vector<>();
//增加一个观察者
public void addObserver(Observer observer) {
this.oVector.add(observer);
}
//删除一个观察者
public void deleteObserver(Observer observer) {
this.oVector.remove(observer);
}
//通知所有观察者
public void notifyObserver() {
for(Observer observer : this.oVector) {
observer.update();
}
}
}
抽象观察者Observer
在这里要说明一下,原作者将这个解释为抽象观察者,其实是有点不太准确的,这里应该是抽象观察者更新接口,这个是每个观察者必须要实现的接口,因为被观察者更新动态后是通过调用这个接口来通知所有观察者的,为什么要用接口而不是抽象类呢?其实接口是一个动作,而类是一个属性,比如人类具有的属性就是手,但是有手不一定要打人,而打人这个动作就是一个接口,你可以打人也可以不打,所以接口可以多继承,因为你除了打这个动作还有很多动作,比如踢人,但是抽象类不同,一旦继承了抽象类就必须实现里面的所有抽象方法,比如继承人类那就要实现手和脚这两个属性或方法。
public interface Observer {
//更新
public void update();
}
具体主题 (ConcreteSubject)
public class ConcreteSubject extends Subject {
//具体业务
public void doSomething() {
//...
super.notifyObserver();
}
}
具体观察者(ConcreteObserver)
public class ConcreteObserver implements Observer {
@Override
public void update() {
System.out.println("收到消息,进行处理");
}
}
Client客户端
public class Client {
public static void main(String[] args) {
//创建一个主题
ConcreteSubject subject = new ConcreteSubject();
//定义一个观察者
Observer observer = new ConcreteObserver();
//观察
subject.addObserver(observer);
//开始活动
subject.doSomething();
}
}
Python代码实现
from abc import ABC, abstractmethod
'''抽象主题(Subject)角色'''
class Subject:
def __init__(self):
self.ovector = [] #观察者列表
'''增加一个观察者'''
def add_observer(self, observer):
self.ovector.append(observer)
'''删除一个观察者'''
def delet_observer(self, observer):
self.ovector.pop(observer)
'''通知所有观察者'''
def notify_observer(self):
for observer in self.ovector:
if object is not None:
observer.update()
'''抽象观察者Observer'''
class Observer(ABC):
'''更新方法'''
@abstractmethod
def update(self):
pass
'''具体主题(ConcreteSubject)'''
class ConcreteSubject(Subject):
def __init__(self):
super().__init__()
'''具体业务'''
def do_something(self):
self.notify_observer()
'''具体观察者(ConcreteObserver)'''
class ConcreteObserver(Observer):
def update(self):
print('收到消息,进行处理')
if __name__ == "__main__":
subject = ConcreteSubject() #创建一个主题
observer = ConcreteObserver() #定义一个观察者
subject.add_observer(observer) #订阅
subject.do_something() #开始通知
实战演练
实现一个微信朋友圈类似的功能,创建一个女生的微信和三个男生的微信,然后女生加男生的微信,最后女生发朋友圈,男生能看到女生的朋友圈,用微信朋友圈来形容观察者模式应该是很一个很好的例子了
from abc import ABC, abstractmethod
'''抽象主题(Subject)角色'''
class Subject:
def __init__(self):
self.ovector = [] # 观察者列表
'''增加一个观察者'''
def add_observer(self, observer):
self.ovector.append(observer)
'''删除一个观察者'''
def delet_observer(self, observer):
self.ovector.pop(observer)
'''通知所有观察者'''
def notify_observer(self, msg):
for observer in self.ovector:
if observer is not None:
observer.update(msg)
'''抽象观察者Observer'''
class Observer(ABC):
'''更新方法'''
@abstractmethod
def update(self, msg):
pass
'''具体主题(ConcreteSubject)'''
class ConcreteSubject(Subject):
def __init__(self, name):
super().__init__()
self.msg = None
self.name = name
'''具体业务'''
def edit_msg(self, msg):
self.msg = msg
print(self.name + ":" + msg)
def send_msg(self):
self.notify_observer(self.msg)
'''具体观察者(ConcreteObserver)'''
class ConcreteObserver(Observer):
def __init__(self, name):
self.name = name
def update(self, msg):
if msg.startswith(self.name):
print(self.name+':'+'???')
return
print(self.name+ ":" + '吃瓜+1')
if __name__ == "__main__":
girl = ConcreteSubject('girl') # 创建女生girl微信
boy1 = ConcreteObserver('boy1') # 创建一个男生boy1微信
boy2 = ConcreteObserver('boy2') # 创建一个男生boy2微信
boy3 = ConcreteObserver('boy3') # 创建一个男生boy3微信
girl.add_observer(boy1) # 加好友
girl.add_observer(boy2) # 加好友
girl.add_observer(boy3) # 加好友
girl.edit_msg('boy2 你这个渣男') # girl编辑一条朋友圈
girl.send_msg() # 发送朋友圈
运行结果有点意思,[手动吃瓜]!
girl:boy2 你这个渣男
boy1:吃瓜+1
boy2:???
boy3:吃瓜+1
这里需要注意的是python中并没有接口和虚方法的概念,所以需要用@abstractmethod方法来实现抽象接口