【问题标题】:Observer pattern updating after unsubscribing退订后观察者模式更新
【发布时间】:2022-01-07 23:58:32
【问题描述】:

我目前正在尝试在 List 类上实现观察者设计模式。列表类是主题,计算类是观察者。计算类需要观察列表类,在列表类中计算列表中的值的总和。然而,当观察者从列表中取消订阅时,它仍然在获取更新。如果观察者订阅了一个新列表,取消订阅之前的列表仍然显示。有人对为什么会发生这种情况有任何提示吗?

from abc import ABCMeta, abstractmethod

class Observer(metaclass = ABCMeta):
    @abstractmethod
    def update(self, data):
        pass
    
class Subject(metaclass = ABCMeta):
    
    @abstractmethod
    def subscribe(self, observer):
        pass

    @abstractmethod
    def unsubscribe(self, observer):
        pass

    @abstractmethod
    def notify(self):
        pass


class List(Subject):
    
    def __init__(self):
        self.__list = []
        self._observers = set()
        
    def add(self, data):
        self.__list.append(data)
        self.notify()
        
    def subscribe(self, observer):
        self._observers.add(observer)
        
    def unsubscribe(self, observer):
        self._observers.discard(observer)
        
    def notify(self):
        for obs in self._observers:
            obs.update(self.__list)


class Calculate(Observer):
    
    def __init__(self, lst):
        self.__data = []
        self._list = lst
        self._list.subscribe(self)
        
    def update(self, data):
        self.__data = data
        
    def calculate(self):
        total = 0
        for item in self.__data:
            total += item
        return total
    
    def remove(self):
        self._list.unsubscribe(self)
        
    def attach(self, lst):
        self._list.subscribe(self)

所以,这是我的测试和我得到的输出:

first_list = List()
first_list.add(1)
list_observer = Calculate(first_list)
first_list.add(5)
list_observer.calculate()

这将返回 6,这是正确的。但是,当我这样做时:

list_observer.remove()
first_list.add(5)
list_observer.calculate()

我得到 11。从某种意义上说,这是正确的计算,但由于观察者取消订阅,为什么它仍然得到更新?我也尝试订阅一个新列表,但旧数据仍在其中。

【问题讨论】:

    标签: python design-patterns observer-pattern


    【解决方案1】:

    这与您传递的数据类型有关。数据列表是可变的。我不能很好地解释它,但这个答案就是你要找的。​​p>

    How do I pass a variable by reference?

    您可以通过这样做来修复它,您可以复制原始对象:

        def update(self, data):
            self.__data = data.copy()
    

    【讨论】:

    • 我试过了,它确实解决了不再获得更新的问题。但是,如果观察者订阅了不同的列表,旧列表仍然存在。
    猜你喜欢
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 2016-02-20
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多