🐈 【Python】デザインパターン学習 - Observerパターン -
作成日: 2021/07/09
0

注意)このTicketはあくまで自分用のメモ。厳密な定義などは参考サイトを参照のこと

Observerパターンについて学ぶ

参考サイト1の動画で紹介されているJavsScriptのコードを自分なりにpythonに書き直して学習する。今回はグラフ表示のためmatplotlibを利用した。もし実行する場合は下記を実行すること。

pip install matplotlib

Observerパターンとは

参考サイト1を参照、分かりやすい。

pythonで書いてみた

import matplotlib as mpl
mpl.use('Agg') # backendsを指定する
import matplotlib.pyplot as plt

'''
入力データ:x座標のデータとy座標のデータが交互に登場して半角スペースで区切って列挙してあるものとする
入力データ例:10 30 20 20 30 40
'''

class Subject():
    def __init__(self):
        self.observers = []
    
    def add(self,observer):
        self.observers.append(observer)
    
    def notify(self):
        for observer in self.observers:
            observer.update()

class GraphModel(Subject):
    def __init__(self):
        super().__init__()
        self.data = []
    
    def sync(self,data):
        self.data = data
        self.notify()

class ChartView():
    def __init__(self,model):
        self.model = model
        self.model.add(self)
    
    def generateGraphData(self):
        self.labels = list(map(self.generateLabel, self.model.data[0::2]))
        self.vals = list(map(int, self.model.data[1::2]))
    
    def generateLabel(self,label):
        return str(label) + "'s"
    
    def update(self):
        self.render()

class Figure():
    def __init__(self,fig,order):
        self.ROW = 3
        self.COLUMN = 1
        self.order = order
        self.fig = fig
    
    def addPlot(self):
        self.fig.add_subplot(self.ROW,self.COLUMN,self.order)

class LineChartView(ChartView,Figure):
    def __init__(self, model, fig, order):
        ChartView.__init__(self,model)
        Figure.__init__(self,fig,order)
    
    def render(self):
        self.generateGraphData()
        self.addPlot()
        plt.plot(self.labels, self.vals)

class BarChartView(ChartView,Figure):
    def __init__(self, model, fig, order):
        ChartView.__init__(self,model)
        Figure.__init__(self,fig,order)
    
    def render(self):
        self.generateGraphData()
        self.addPlot()
        plt.bar(self.labels, self.vals)

class PieChartView(ChartView,Figure):
    def __init__(self, model, fig, order):
        ChartView.__init__(self,model)
        Figure.__init__(self,fig,order)
    
    def render(self):
        self.generateGraphData()
        self.addPlot()
        plt.pie(self.vals,labels=self.labels)
    
if __name__=='__main__':
    
    MODEL = GraphModel()
    fig = plt.figure()
    PieChartView(MODEL,fig,order=1)
    LineChartView(MODEL,fig,order=2)
    BarChartView(MODEL,fig,order=3)

    MODEL.sync(input().split())
    
    plt.savefig("hoge.png") 

入力データ

10 30 20 10 30 40

実行結果

hoge.png

書いた感想

Observerパターンを利用しないパターンをまず書いて、次に利用するパターンを書いてみた。ObserverパターンのSubjectがObserverを追加して、追加したObserverに通知を送る。通知を送られたObserverが決まった動作をする。という一連の流れを実装したが、別にこの流れでなくても実装自体は可能だった。ただ、Observerパターンに沿うようにコードを書いているときに徐々に変更や追加に強い、疎結合のコードになっていっているのを感じた。

Observerパターン どういったときに使う?

オブジェクトの状態が変化したときに、それを通知して、通知を受けったオブジェクトが処理を実行するといった仕組みを作るときに使える。参考サイト1では主にフロントエンドの実装で使うことが多いと言っていたが、下記例のようにバックエンドでも使える仕組み。
例.

エクセルのようにデータがあってグラフが複数あるときに、データが変更されたらグラフの表示を変えるときに使える。(参考サイト1)

メーリングリストで、何らかのイベント(新製品情報など)があったとき、購読者リストに登録している人にメッセージを送る。(参考サイト3から引用)

書いたコード

github
nousecase.py:Observerパターンを利用しないでグラフを表示するコード。何をやっているのか理解するのに便利。
usecase.py:上記に表記したコード。Observerパターンを利用している。

参考サイト

  1. Observerパターン【概念解説】- プログラミング相談所オンライン
  2. Observerパターン【コードで理解する】- プログラミング相談所オンライン
  3. wiki:Observer パターン
フリーランスでpythonエンジニアとして働きたく勉強中。 前職は運用SEとセキュリティエンジニア。 開発は学校で学んだ経験と趣味でやっていた程度。一応前職でも業務の自動化のためにExcel VBAやセキュリティテスト用のWebサイトの開発やセキュリティテストツールの改良などで開発はやっていた。