2010年11月25日木曜日

第14章 Chain of Responsibilityパターン : 責任のたらい回し



今回はChain of Responsibility。UIなどでよく使われるパターンだそうです。

というのも、UIはビューコンポーネントのようなものを入れ子にして構成されることが多く、
(WindowCanvasTextField 的な)
そのUIをユーザがクリック(タップ)したりキーボード操作したりする『要求』に対し、その要求をどのコンポーネントが処理するかは、普通『たらい回し』にされることが多いからです。
(上の例だと TextField → Canvas → Window)

すなわち、Chain of Responsibilityパターンは

  • (主にユーザなどによる)要求があり
  • その要求の処理先を動的に設定したい

時に最適なパターンと言えそうです。

また、Compositeパターンなどの再帰的構造でよく使うそうです。



実行結果
[0] is resolved by [Bob].
[33] is resolved by [Bob].
[66] is resolved by [Bob].
[99] is resolved by [Bob].
[132] is resolved by [Danie].
[165] is resolved by [Danie].
[198] is resolved by [Danie].
[231] is resolved by [Elmo].
[264] is resolved by [Fred].
[297] is resolved by [Elmo].
[330] cannot be resolved.
[363] is resolved by [Elmo].
[396] cannot be resolved.
[429] is resolved by [Charlie].
[462] cannot be resolved.
[495] is resolved by [Elmo].

ソースコード
#!/usr/bin/env python
# -*- coding: utf8 -*-

class Trouble:
    def __init__(self, number): self.number = number
    def __str__(self): return "[%d]" % (self.number)


class Support:
    def __init__(self): raise Exception("Abstract class")
    def __str__(self): return "[%s]" % self.name

    # final method - template method
    def support(self, trouble):
        if self._resolve(trouble):
            self._done(trouble)
        elif self.next is not None:
            self.next.support(trouble)
        else:
            self._fail(trouble)

    def _resolve(self, trouble): raise NotImplementedError
    def _done(self, trouble): print "%s is resolved by %s." % (trouble, self)
    def _fail(self, trouble): print "%s cannot be resolved." % (trouble)

    def setNext(self, next):
        self.next = next
        return self.next


class NoSupport(Support):
    def __init__(self, name):
        self.name = name
        self.next = None

    def _resolve(self, trouble): return False


class LimitSupport(Support):
    def __init__(self, name, limit):
        self.name = name
        self.limit = limit
        self.next = None

    def _resolve(self, trouble):
        return True if trouble.number < self.limit else False


class OddSupport(Support):
    def __init__(self, name):
        self.name = name
        self.next = None

    def _resolve(self, trouble):
        return True if trouble.number % 2 == 1 else False


class SpecialSupport(Support):
    def __init__(self, name, number):
        self.name = name
        self.number = number
        self.next = None

    def _resolve(self, trouble):
        return True if trouble.number == self.number else False


def main():
    m_alice = NoSupport("Alice")
    m_bob = LimitSupport("Bob", 100)
    m_charlie = SpecialSupport("Charlie", 429)
    m_danie = LimitSupport("Danie", 200)
    m_elmo = OddSupport("Elmo")
    m_fred = LimitSupport("Fred", 300)

    m_alice.setNext(m_bob).setNext(m_charlie).setNext(m_danie).setNext(m_elmo).setNext(m_fred)

    for i in xrange(0, 500, 33):
        m_alice.support(Trouble(i))

if __name__=='__main__': main()

0 件のコメント:

コメントを投稿