《付録》VisitorBrush.py
# -*- coding: utf-8 -*- #=============================================================================== # Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部 # # History: WPF examples # 2008/01/25, IronPython 1.1.1 (download) # 2008/08/22, IronPython 1.1.2 (download) # 2008/03/16, ver.2.0, WPF # 2008/00/00, ver.2.1, IronPython 1.1.2 #=============================================================================== from _ant import * from System import * from System.Windows import * from System.Windows.Media import * from System.Windows.Media.Imaging import * from System.Windows.Shapes import * ## -------------------- # Visitor::Element class XShape: def accept(self, v): source = "v.visit_%s(self)"%self.__class__.__name__ eval(source) ; print source ## -------------------- # Visitor::ConcreteElement class EllipseShape(XShape): def __init__(self): self.shape = Ellipse( Stroke=Brushes.Blue, StrokeThickness=2, Width=100, Height=50, ) ## -------------------- # 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, ) ## -------------------- # 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__) ## -------------------- # Visitor::ConcreteVisitor class SolidColorVisitor(XVisitor): def visit_EllipseShape(self, e): e.shape.Fill = Brushes.Yellow def visit_PolygonShape(self, e): e.shape.Stroke = Brushes.Black ## -------------------- # Visitor::ConcreteVisitor class LinearGradientVisitor(XVisitor): def visit_EllipseShape(self, e): brush = LinearGradientBrush() for color, offset in [ ("Yellow", 0.0), ("Green" , 1.0), ]: brush.GradientStops.Add(GradientStop( Color=getattr(Colors, color), Offset=offset, )) e.shape.Fill = brush def visit_PolygonShape(self, e): e.shape.Stroke = Brushes.Black ## -------------------- # Visitor::ConcreteVisitor class RadialGradientVisitor(XVisitor): def visit_EllipseShape(self, e): brush = RadialGradientBrush() for color, offset in [ ("Yellow", 0.0), ("Green" , 1.0), ]: brush.GradientStops.Add(GradientStop( Color=getattr(Colors, color), Offset=offset, )) e.shape.Fill = brush def visit_PolygonShape(self, e): e.shape.Stroke = Brushes.Black ## -------------------- # 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 ## -------------------- # Visitor::ConcreteVisitor class DrawingVisitor(XVisitor): def visit_EllipseShape(self, e): brush = DrawingBrush( Viewport=Rect(0, 0, 0.1, 0.1), TileMode=TileMode.Tile, ) sheet = GeometryDrawing( brush=Brushes.Yellow, pen=None, geometry=RectangleGeometry(Rect(0, 0, 50, 50))) geometry = GeometryGroup() for (px, py), rx, ry in ( *1 marble = GeometryDrawing( brush=Brushes.Blue, pen=None, geometry=geometry) drawing = DrawingGroup() for g in sheet, marble: drawing.Children.Add(g) brush.Drawing = drawing e.shape.Fill = brush def visit_PolygonShape(self, e): e.shape.Stroke = Brushes.Black ## -------------------- # 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 ## -------------------- # Visitor::ObjectStructure class ExWindow(Window): def __init__(self, Content=None, **args): self.InitializeComponent(Content) self.init() def InitializeComponent(self, Content): self.Content = LoadXaml(Content) def init(self): target = ( "solidColorBrush", "linearGradientBrush", "radialGradientBrush", "imageBrush", "drawingBrush", "visualBrush", ) self._Controls(target) def _Controls(self, target): controls = xaml_controls(self) for e in target: setattr(self, e, controls[e]) visitors = ( SolidColorVisitor(), LinearGradientVisitor(), RadialGradientVisitor(), ImageVisitor(), DrawingVisitor(), VisualVisitor(self.imageBrush), ) for e, v in zip(target, visitors): items = getattr(self, e) for s in EllipseShape(), PolygonShape(): s.accept(v) items.Children.Add(s.shape) ## -------------------- if __name__ == "__main__": xaml = __file__.replace(".py",".xaml") win = ExWindow( Title=xaml, Width=280, Height=200, Content=xaml, ) Application().Run(win) ## --------------------
*1:10, 10), 10, 10), ((35, 35), 15, 15), ): geometry.Children.Add(EllipseGeometry( Center=Point(px, py), RadiusX=rx, RadiusY=ry,
《付録》VisitorBrush.xaml
<!-- # Copyright (C) 2000-2008, (^.^) piyo-piyo Tamago-Club # # History: WPF examples # 2008/01/25, IronPython 1.1.1 (download) # 2008/08/22, IronPython 1.1.2 (download) # 2008/03/16, ver.2.0, WPF # 2008/00/00, ver.2.1, IronPython 1.1.2 --> <TabControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/sparkle"> <!-- SolidColorBrush --> <TabItem Header="SolidColorBrush"> <WrapPanel Name="solidColorBrush" /> </TabItem> <!-- LinearGradientBrush --> <TabItem Header="LinearGradientBrush"> <WrapPanel Name="linearGradientBrush" /> </TabItem> <!-- RadialGradientBrush --> <TabItem Header="RadialGradientBrush"> <WrapPanel Name="radialGradientBrush" /> </TabItem> <!-- ImageBrush --> <TabItem Header="ImageBrush"> <WrapPanel Name="imageBrush" /> </TabItem> <!-- DrawingBrush --> <TabItem Header="DrawingBrush"> <WrapPanel Name="drawingBrush" /> </TabItem> <!-- VisualBrush --> <TabItem Header="VisualBrush"> <WrapPanel Name="visualBrush" /> </TabItem> </TabControl>
Visitor パターンに加えて
古典的な Visitor パターンに捕われることなく、動的な問題解決を導入したのが、サンプルファイル VisitorBrush.py です。
具体的な WPF コントロール(TabControl/TabItem/WrapPanel)に関する情報は、マークアップを使って VisitorBrush.xaml ファイルの中に封じ込めてあるので、分離コードでは、それに依存しない部分だけを記述するように努めます。
## -------------------- # Visitor::ObjectStructure class ExWindow(Window): def _Controls(self, target): controls = xaml_controls(self) for e in target: setattr(self, e, controls[e]) visitors = ( SolidColorVisitor(), LinearGradientVisitor(), RadialGradientVisitor(), ImageVisitor(), DrawingVisitor(), VisualVisitor(self.imageBrush), ) for e, v in zip(target, visitors): items = getattr(self, e) for s in EllipseShape(), PolygonShape(): s.accept(v) items.Children.Add(s.shape)
すべての問題解決を静的(コンパイル時)に図るのではなく、それを動的(実行時)に委ねられるので、些末な状況に煩わされることなく、本質的な問題解決に専念できます。対象となる要素(EllipseShape/PolygonShape)と、それを表現する手段(SolidColorVisitor/LinearGradientVisitor/RadialGradientVisitor/ImageVisitor/DrawingVisitor/VisualVisitor)に関する問題提起を、事前に用意するだけで、事後の問題解決は、当事者に委ねるのを基調とします。
必要なときに Iterator を生成して、その機能を要求する立場(what)では組み込みの制御構造(for 文)を利用するだけです。すると、その要求を実現する立場(how)とは独立した記述が可能になります。
このように、さまざまな観点から役割分担を促進することで、複雑なアプリケーション開発の負荷を明確に分散できるようになります。さらに、機能を実現する方法に変更があっても、これに柔軟に対処できるようになります。