《38》デザインパターン〈GoF〉Template〈Python 3.0 版〉
実録:はじめてのプログラミング《記事一覧》
《38》デザインパターン〈GoF〉Template
《著》小粒ちゃん+α《監修》小泉ひよ子とタマゴ倶楽部
第3版♪2009/02/28 ● 2009年3月6日(金)
■ 概要
デザインパターン〈GoF〉Template を適用した事例を紹介します。
Template を適用すると、それを実現する手段に依存しない抽象的な記述が可能になります。 すると、簡潔で見通しの良いコードを記述できるようになり、アジャイル開発を促進します。
■ 関連記事
デザインパターン〈GoF〉Template
カタログには〈GoF〉Template として紹介されている、デザインパターンは、ここでもその効能を発揮します。《前述》した3つののメソッドはすべて、次のように、
def __delitem__(self, key): self.removeNode(key, "delitem") def remove(self, value): self.removeNode(value, "remove") def pop(self): return self.removeNode(None, "pop")
メソッド removeNode を再利用しているので、その違いを実引数("delitem"/"remove"/"pop")で指定できます。これらのメソッドの違いは、テンプレートを通して見ると、次のように、
def __delitem__(____, key): ____.__________(key, "delitem") def remove(____, value): ____.__________(value, "remove") def pop(____): return ____.__________(None, "pop")
その違いだけが浮き彫りになります。また、先述した、
def _removeNode_delitem(self, prev, node): return self._removeNode_body(prev, node) def _removeNode_remove(self, prev, node): return self._removeNode_body(prev, node) def _removeNode_pop(self, prev, node): self.tail = prev return self._removeNode_body(prev, node, node.item)
についても同様に、テンプレートを通して見ると、次のように、
def _removeNode_delitem(____, ____, node): return ____.________________(____, ____) def _removeNode_remove(____, ____, node): return ____.________________(____, ____) def _removeNode_pop(____, ____, node): self.tail = prev return ____.________________(____, ____, node.item)
その違いだけが浮き彫りになります。さらに、これらの違いを具体的に知りたいときには、たとえば、
def _removeNode_delitem_cond(self, node, key, n): return n==key # 添字が一致する def _removeNode_remove_cond(self, node, value, n): return node.item==value # 値 が一致する def _removeNode_pop_cond(self, node, value, n): return node==self.tail # 末尾と一致する
という具合に、各機能に固有の問題解決に専念できる〔関心の分離〕という効果が期待できます。最後に、リファクタリングの成果を示すと、次のようになります。
class myList(object): def removeNode(self, value, tag): prev, node = self.head, self.head.next n = 0 while node: if eval("self._removeNode_%s_cond(node,value,n)"%tag): return eval("self._removeNode_%s(prev,node)"%tag) prev, node = node, node.next n += 1 else: s = self.__class__.__name__ eval("self._removeNode_%s_error(s)"%tag) def _removeNode_body(self, prev, node, value=None): prev.next = node.next del node return value
すると、新たなメソッド XXX を追加したいときには、テンプレート関数 removeNode を利用して、3つのメソッド _removeNode_XXX_cond/_removeNode_XXX/_removeNode_XXX_error にその違い(そのメソッドに固有の状況)を記述するだけです。
Tips
Last updated♪09/04/25