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 expressions
publish 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, the
NumberGenerator` 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, the
RandomNumberGenerator` 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