As a material for learning GoF design patterns, the book "Introduction to Design Patterns Learned in the Augmented and Revised Java Language" seems to be helpful. However, since the examples taken up are based on JAVA, I tried the same practice in Python to deepen my understanding.
The Observer pattern is a type of design pattern used in the process of notifying other objects of an event (event) of an object in the program. This is called because the object side to be notified is observed by the object side to be notified (English: observe). Also known as the publish-subscribe model. It is closely related to the principle of implicit calling. It is also used to implement a distributed event processing system. Depending on the language, the problems dealt with in this pattern are handled by the language's event handling syntax.
UML class and sequence diagram
UML class diagram

(The above is quoted from Wikipedia)
In the ʻObserver pattern, when the state of the observation target changes, the observer is notified, so it seems to be effective when describing the processing according to the state change. The original meaning of the word ʻobserver is" observer ", but in reality, the role of ʻObserver is passive rather than actively" observing "but being" notified "by the role of Subject. It is said that it is sometimes called the Publish-Subscribepattern because it will be waiting for you. Certainly, I felt that the expressionspublish and subscribe` were more appropriate.
Actually, I would like to run a sample program that utilizes the Observer pattern and check the following behavior.
――The observer observes the object that generates a lot of numbers and displays the value.
――The display method differs depending on the observer.
--DigitalObserver displays the value numerically
--GraphicObserver displays the values in a simple graph
$ python Main.py
DigitObservser: 30
GraphicObserver:******************************
DigitObservser: 48
GraphicObserver:************************************************
DigitObservser: 6
GraphicObserver:******
DigitObservser: 19
GraphicObserver:*******************
DigitObservser: 19
GraphicObserver:*******************
DigitObservser: 45
GraphicObserver:*********************************************
DigitObservser: 8
GraphicObserver:********
DigitObservser: 21
GraphicObserver:*********************
DigitObservser: 40
GraphicObserver:****************************************
DigitObservser: 6
GraphicObserver:******
DigitObservser: 1
GraphicObserver:*
DigitObservser: 9
GraphicObserver:*********
DigitObservser: 26
GraphicObserver:**************************
DigitObservser: 22
GraphicObserver:**********************
DigitObservser: 16
GraphicObserver:****************
DigitObservser: 10
GraphicObserver:**********
DigitObservser: 45
GraphicObserver:*********************************************
DigitObservser: 1
GraphicObserver:*
DigitObservser: 36
GraphicObserver:************************************
DigitObservser: 45
GraphicObserver:*********************************************
Similar code has been uploaded to the Git repository. https://github.com/ttsubo/study_of_design_pattern/tree/master/Observer
--Directory structure
.
├── Main.py
└── observer
├── __init__.py
├── generator.py
└── observer.py
The Subject role represents the" observed side ". The Subject role has a method for registering the observer ʻObserverrole and a method for deleting it. It also declares a "get current state" method. In the sample program, theNumberGenerator` class serves this role.
observer/generator.py
import random
from abc import ABCMeta, abstractmethod
class NumberGenerator(metaclass=ABCMeta):
def __init__(self):
self.__observers = []
def addObserver(self, observer):
self.__observers.append(observer)
def deleteObserver(self, observer):
self.__observers.remove(observer)
def notifyObserver(self):
for o in self.__observers:
o.update(self)
@abstractmethod
def getNumber(self):
pass
@abstractmethod
def execute(self):
pass
The Concrete Subject role is a role that expresses a concrete" observed side ". When the state changes, tell the registered ʻObserverrole. In the sample program, theRandomNumberGenerator` class serves this role.
observer/generator.py
class RandomNumberGenerator(NumberGenerator):
def __init__(self):
self.__number = 0
super(RandomNumberGenerator, self).__init__()
def getNumber(self):
return self.__number
def execute(self):
for _ in range(20):
self.__number = random.randint(0, 49)
self.notifyObserver()
The role of ʻObserver is the role of being told by the role of Subject that "the state has changed". The method for that is ʻupdate.
In the sample program, the ʻObserver` class serves this role.
observer/observer.py
import time
from abc import ABCMeta, abstractmethod
class Observer(metaclass=ABCMeta):
@abstractmethod
def update(self, ganerator):
pass
The ConcreteObserver role is the concrete ʻObserver. When the ʻupdate method is called, it gets the current state of the Subject role in that method.
In the sample program, the DigitObserver and GraphObserver classes serve this role.
observer/observer.py
class DigitObserver(Observer):
def update(self, generator):
print("DigitObservser: {0}".format(generator.getNumber()))
time.sleep(0.1)
class GraphObserver(Observer):
def update(self, generator):
print("GraphicObserver:", end='')
count = generator.getNumber()
for _ in range(count):
print('*', end='')
print("")
time.sleep(0.1)
In the sample program, the startMain method serves this role.
Main.py
from observer.observer import DigitObserver, GraphObserver
from observer.generator import RandomNumberGenerator
def startMain():
generator = RandomNumberGenerator()
observer1 = DigitObserver()
observer2 = GraphObserver()
generator.addObserver(observer1)
generator.addObserver(observer2)
generator.execute()
if __name__ == '__main__':
startMain()
-[Finishing "Introduction to Design Patterns Learned in Java Language" (Not)](https://medium.com/since-i-want-to-start-blog-that-looks-like-men-do/java Introduction to Design Patterns Learned in Language-Finishing-Not-2cc9b34a30b2)
Recommended Posts