1a)対象となる要素:Element
Visitor::Element では、対象とする要素に共通するプロトコルを規定します。
## -------------------- # Visitor::Element class XShape: def accept(self, v): source = "v.visit_%s(self)"%self.__class__.__name__ eval(source) ; print source
多種多様な対象を扱いたいときに、それらの違いを捨象するとともに、動的な問題解決が可能になるメカニズムが提供されていると、便利です。すると、XShape の傘下では、個別にメソッド accept を用意する必要がなくなります。次のような(単調な)コードを何度も繰り返し記述することを想像すると、その効用が分かります。
## -------------------- class EllipseShape: # ('.')def accept(self, v): v.visit_EllipseShape(self)class PolygonShape: # (-.-)def accept(self, v): v.visit_PolygonShape(self)class BooShape: # (=.=)def accept(self, v): v.visit_BooShape(self)
どのメソッドを必要とするかは、実行時にオブジェクト自身 self に決定させるのが得策です。「クラス」指向から「オブジェクト」指向への扉を開く鍵は、こんなところにも落ちています。
《Tips》 未熟な OOP 言語仕様のツケをパターンで清算する憂き目(力仕事:ハードコーディング)から、プログラマーを解放します。単調な作業の繰り返しは、得てして後で見つけるのが困難なバグを誘発しがちです。ハードウェア/ソフトウェアの特性を知ることで、プログラム(算譜)の質の向上が期待できるのと同様に、ヘッドウェアの特性を知っておくと、プログラミング(作譜)の質の向上が期待できます。□
1b)対象となる要素:ConcreteElement
Visitor::ConcreteElement では、Visitor::Element で規定されたプロトコルに従いながら、対象とする要素に固有の特性を実現します。
## -------------------- # Visitor::ConcreteElement
class EllipseShape(XShape):
def __init__(self):
self.shape = Ellipse(
Stroke=Brushes.Blue,
StrokeThickness=2,
Width=100,
Height=50,
)
対象とする要素のひとつが、ここで取り上げた Ellipse です。
## -------------------- # Visitor::ConcreteElement
class PolygonShape(XShape):
def __init__(self):
points = PointCollection()
vertices = "0,28 80,28 12,80 40,0 68,80"
for e in vertices.split(" "):
x, y = eval(e)
points.Add(Point(x, y))
self.shape = Polygon(
Stroke=Brushes.Blue,
StrokeThickness=2,
Points=points,
)
対象とする要素のひとつが、ここで取り上げた Polygon です。
《Tips》 この事例では、ひとつのモジュールを扱っていますが、実際の開発では、個別にモジュールを用意します。要求仕様の変更に伴い、新たな対象を扱いたいときには(Open)モジュールを追加するだけです。このとき(Closed)既存のモジュールはその影響を受けません。すると、開放閉鎖原則(OCL: Open-Closed Principle)に沿ったアプローチが可能になります。□
適用事例: Visitor パターン
多種多様な対象を扱うとともに動的な問題解決を図りたいとき、すぐに思い浮かぶのは古典的な〈GoF〉Visitor パターンです。そこで、前述した事例に、このパターンを適用してみます。すると、要求仕様の変更に伴って新たな対象を取り込みたいときに、既存のリソースに影響を与えることなく、その対象ごとに最適な表現手段(選択肢)を独立して扱えるようになります。
まず、パターンの復習から始めます。古典的な Visitor パターンを踏襲したのが、VisitorBrush.py です。
>ipy.exe VisitorBrush.py
このアプリケーションを起動すると、ウィンドウが現れます。1)任意のタブをクリックすると、2)選択したブラシ使って描画した図形が左側に表示されます。右側の図形は、外枠だけが表示されます。これは、将来の機能変更に伴って、新たな表現手段が可能になったときに、その動作を確認できる余地を残したもので、Visitor パターンの顕著な効用のひとつです。