Другое дело например паттерн Observer. Он относится к паттернам поведения и реализует обработку событий. Реализуется связь один ко многим, между объектом и зависимыми от него компонентами. При изменении состояния объекта, все зависимые компоненты оповещаются и изменяются автоматически.
Вот простейшая реализация этого шаблона:
class Subject: def __init__(self): self._observers = [] def attach(self, observer): if not observer in self._observers: self._observers.append(observer) def detach(self, observer): try: self._observers.remove(observer) except ValueError: pass def notify(self, modifier=None): for observer in self._observers: if modifier != observer: observer.update(self) # Example usage class Data(Subject): def __init__(self, name=''): Subject.__init__(self) self.name = name self.data = 0 def setData(self, data): self.data = data self.notify() def getData(self): return self.data class HexViewer: def update(self, subject): print 'HexViewer: Subject %s has data 0x%x' % (subject.name, subject.getData()) class DecimalViewer: def update(self, subject): print 'DecimalViewer: Subject %s has data %d' % (subject.name, subject.getData()) # Example usage... def main(): data1 = Data('Data 1') data2 = Data('Data 2') view1 = DecimalViewer() view2 = HexViewer() data1.attach(view1) data1.attach(view2) data2.attach(view2) data2.attach(view1) print "Setting Data 1 = 10" data1.setData(10) print "Setting Data 2 = 15" data2.setData(15) print "Setting Data 1 = 3" data1.setData(3) print "Setting Data 2 = 5" data2.setData(5) print "Detach HexViewer from data1 and data2." data1.detach(view2) data2.detach(view2) print "Setting Data 1 = 10" data1.setData(10) print "Setting Data 2 = 15" data2.setData(15) if __name__ == '__main__': main()
В примере в принципе все понятно из кода. Мы заводим специальный класс способный подписывать, отписывать и оповещать наблюдателей и наследуем от него основной класс. У наблюдателей соответственно должны присутствовать специальные интерфейсы для работы с событиями.
Вот пример посложнее:
Допустим у нас есть объект-таймер, каждую секунду оповещающий подписанных на него наблюдателей о своем изменении. Код класса этого объекта может выглядеть так:
class ClockTimer: def GetHour(self): return self._hour def GetMinute(self): return self._minute def GetSecond(self): return self._second TickEvent = Event() def OnTick(self): ClockTimer.TickEvent.call(self, self.GetHour(), self.GetMinute(), self.GetSecond()) def Tick(self): # update internal time-keeping state # ... self.OnTick()
Каждую секунду вызывается метод onTick который должен информировать наблюдателей о изменениях. Теперь мы можем создать наблюдателя, например класс цифровых часов, который подпишется на изменения таймера:
class DigitalClock(Widget): def __init__(self, clockTimer): self.__subject = clockTimer clockTimer.TickEvent += self.Update def close(self): self.__subject.TickEvent -= self.Update def Update(self, subject, hour, min, sec): self.displayedTime = (hour, min, sec) self.Draw() def Draw(self): # draw the digital clock
Создадим вспомогательный класс Delegate, способный манипулировать коллекцией методов или функций, мы же не знаем сколько наблюдателей подпишутся на изменения.
class Delegate: '''Handles a list of methods and functions Usage: d = Delegate() d += function # Add function to end of delegate list d(*args, **kw) # Call all functions, returns a list of results d -= function # Removes last matching function from list d -= object # Removes all methods of object from list ''' def __init__(self): self.__delegates = [] def __iadd__(self, callback): self.__delegates.append(callback) return self def __isub__(self, callback): # If callback is a class instance, # remove all callbacks for that instance self.__delegates = [ cb for cb in self.__delegates if getattr(cb, 'im_self', None) != callback] # If callback is callable, remove the last # matching callback if callable(callback): for i in range(len(self.__delegates)-1, -1, -1): if self.__delegates[i] == callback: del self.__delegates[i] return self return self def __call__(self, *args, **kw): return [ callback(*args, **kw) for callback in self.__delegates]
Класс способен принять функцию, удалить функцию и вызвать все функции по порядку. И наконец описываем класс события.
class Event(property): '''Class event notifier Usage: class C: TheEvent = Event() def OnTheEvent(self): self.TheEvent(self, context) instance = C() instance.TheEvent += callback instance.OnTheEvent() instance.TheEvent -= callback ''' def __init__(self): self.attrName = attrName = "__Event_" + str(id(self)) def getEvent(subject): if not hasattr(subject, attrName): setattr(subject, attrName, Delegate()) return getattr(subject, attrName) super(Event, self).__init__(getEvent) def call(self, subject, *args, **kw): if hasattr(subject, self.attrName): getattr(subject, self.attrName)(subject, *args, **kw)
Самое сложное разобраться в классе Event. Его основная задача создать объект Delegate не сразу, а только при необходимости. Итак в DigitalClock мы подписываемся на событие TickEvent, а в ClockTimer зажигаем это событие.
Комментариев нет:
Отправить комментарий