2b)機能の実現:ConcreteVisitor
Visitor::ConcreteVisitor では、Visitor::Visitor で規定されたプロトコルに従って、各機能を実現します。
## -------------------- # Visitor::ConcreteVisitor class ImageVisitor(XVisitor): def visit_EllipseShape(self, e): brush = ImageBrush( ImageSource=BitmapImage( Uri("sunflower.jpg", UriKind.Relative))) e.shape.Fill = brush def visit_PolygonShape(self, e): e.shape.Stroke = Brushes.Black
規定されたプロトコル visit_EllipseShape に従って、対象となる shape を表現するのに最適な方法を実現します。
visit_PolygonShape についても同様ですが、具体的な方法は読者への課題として、残してあります。これをどのように実現するかは、自由です。このとき、他の対象の存在を気にする必要はなく、その対象に関する知識を必要としないのが、このパターンの効能のひとつです。
## -------------------- # Visitor::ConcreteVisitor
class VisualVisitor(XVisitor):
def __init__(self, visual):
self.visual = visual
def visit_EllipseShape(self, e):
brush = VisualBrush()
brush.Visual = self.visual
e.shape.Fill = brush
def visit_PolygonShape(self, e):
e.shape.Stroke = Brushes.Black
ここでは、前述した ImageVisitor とは違って、他の対象の存在を気にする必要はありませんが、「必要なら」その対象 self.visual に関する知識を「利用できる」ことが、このパターンの効能のひとつです。
その他の機能については割愛しますので、付録を参照してください。
2a)機能の要求:Visitor
各機能を実現するときには、Visitor::Visitor で規定されたプロトコルに従います。
## -------------------- # Visitor::Visitor class XVisitor: def visit_EllipseShape(self, e): raise NotImplementedError("%s.visit_EllipseShape" %self.__class__.__name__) def visit_PolygonShape(self, e): raise NotImplementedError("%s.visit_PolygonShape" %self.__class__.__name__)
ここで規定したメソッドを、子孫クラスで再定義しないと、実行時に例外 NotImplementedError を生成するとともに、そのクラス名を出力します。たとえば、メソッド visit_EllipseShape を実現しないと、実行時に次のようなメッセージを出力します。
NotImplementedError: SolidColorVisitor.visit_EllipseShape
すると、子孫クラス SolidColorVisitor で「必須の」メソッドを再定義していないのが分かります。
《Note》 abstract/interface などに象徴されるメカニズムは、些末な作業をコンパイラーに委ねられるので、初心者には重宝するかもしれません。そこに代えて、コンパイラーに任せっきりにするのでなく、プログラマーが自発的なメカニズムを注入できる仕組みがあると、便利です。すると、システム開発の初期に導入された意志決定に束縛される憂き目から解放されます。硬直した作業環境のもとでは、得てして後で見つかる革新的な手法の導入さえ躊躇しがちです。ハードウェア/ソフトウェアの特性を知ることで、プログラム(算譜)の質の向上が期待できるのと同様に、ヘッドウェアの特性を知っておくと、プログラミング(作譜)の質の向上が期待できます。□