Python.use(better)《6》Observer(6)パターン夜明け前

記事一覧《こちらに移動中です》2007年6月18日 (月)

Python.use(better) # Let’s GoForward

Observer(6)パターン夜明け前《Jython2.5.0》

《著》森こねこ・後藤いるか・伊藤うさぎ・小粒ちゃん+∞《監修》小泉ひよ子とタマゴ倶楽部
第1版♪1995/01/29

■ 概要

GoF の事例を鵜呑みにすると、迂遠なアプローチを余儀なくされるばかりか、Python の洗練された特徴を活かせずに損をします。GoF を模写しても始まりません。GoF が模写したその起源を探ることで、パターンの本質に迫れます。Let's Go Forward (^.^)

Observer(6)パターン夜明け前★★

さらに、別のコンポーネントを導入して、これにも対応できるようにします。

 新たなウィンドウを追加します。任意のリスト項目を選択すると、その色情報が文字列としてテキスト領域に表示されます。

class TextView(JTextArea):
    def __init__(self, subject):
        JTextArea.__init__(self,
            lineWrap=True, wrapStyleWord=True)
        self.subject = subject
        self.subject.addObserver(self)
    def redisplay(self):
        color = self.subject.color()
        self.text = ""
        self.append("%s\n"%color)

 追加したクラス TextView は、指定された色情報をテキスト(文字列)を使って表示します。ここでは、JTextArea を再利用しています。
 メソッド __init__ は、(CanvasView のときと同様に)subject の項目が変更されたときに、その旨を自分にも通知するように登録しておきます。すると、subject の状態に、自分 self が依存することになります。
 メソッド redisplay は(CanvasView における paint と違って)項目が変更されたときに、subject から獲得 color() した色情報を、テキストを使って表示ます。

class ColorPanel(JPanel):
    def valueChanged(self, e):
        value = e.source.selectedValue
        self.panelView.background = self.model.color(value)
        if not self.observer: return
        if isinstance(self.observer, CanvasView):
            self.observer.repaint()
        if isinstance(self.observer, TextView):
            self.observer.redisplay()

 変更したクラス ColorPanel は、新たに追加したコンポーネントにも対処します。
 変更したメソッド valueChanged は、自分の最新情報を使って、observer に再描画するように依頼します。このとき、2種類のコンポーネントに対処するためには、observer がどちらに属するインスタンスであるかを判定 isinstance する必要があります。そして、CanvasView なら repaint を使って図形を描き、TextView なら redisplay を使ってテキストを表示します。

 ここで問題となるのは、新たな種類のコンポーネントを追加するごとに、メソッド valueChanged 内に、インスタンスの種類を判定 isinstance するコードを追加する必要があることです。なぜなら、異なる対象 observer ごとに、固有のメソッド repaint/redisplay を呼び出す必要があるからです。この問題を回避するには、異なる対象 observer に対して、同じメソッド呼び出しを可能にすることです。それには、共通するインターフェースを抽出して、これを独立したクラスとして規定するのがよいでしょう。

Last updated♪2009/07/29