トリプルディスパッチ
トリプルディスパッチの例。
// Shape.cs public abstract partial class Shape { public static void Check(Shape sh1, Shape sh2, Shape sh3) { sh1.Check(sh2, sh3); } public abstract void Check(Shape sh1, Shape sh2); public void Show(Shape sh1, Shape sh2) { System.Console.WriteLine("{0} {1} {2}", GetType().Name, sh1.GetType().Name, sh2.GetType().Name); } } // Circle.cs public abstract partial class Shape { public abstract void Check(Circle sh1, Shape sh2); public abstract void Check(Circle sh1, Circle sh2); } public partial class Circle : Shape { public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); } public override void Check(Circle sh1, Shape sh2) {sh2.Check(sh1, this);} public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); } } // Rect.cs public abstract partial class Shape { public abstract void Check(Rect sh1, Shape sh2); public abstract void Check(Rect sh1, Circle sh2); public abstract void Check(Rect sh1, Rect sh2); } public partial class Circle : Shape { public override void Check(Rect sh1, Shape sh2) { sh2.Check(sh1, this); } public override void Check(Rect sh1, Circle sh2) { sh1.Check(this, sh2); } public override void Check(Rect sh1, Rect sh2) { sh1.Check(sh2, this); } } public partial class Rect : Shape { public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); } public override void Check(Circle sh1, Shape sh2) { sh2.Check(this, sh1); } public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); } public override void Check(Rect sh1, Shape sh2) { sh2.Check(sh1, this); } public override void Check(Rect sh1, Circle sh2) { Show(sh1, sh2); } public override void Check(Rect sh1, Rect sh2) { Show(sh1, sh2); } } // Polygon.cs public abstract partial class Shape { public abstract void Check(Polygon sh1, Shape sh2); public abstract void Check(Polygon sh1, Circle sh2); public abstract void Check(Polygon sh1, Rect sh2); public abstract void Check(Polygon sh1, Polygon sh2); } public partial class Circle : Shape { public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); } public override void Check(Polygon sh1, Circle sh2) { sh1.Check(this, sh2); } public override void Check(Polygon sh1, Rect sh2) { sh1.Check(sh2, this); } public override void Check(Polygon sh1, Polygon sh2) { sh1.Check(sh2, this); } } public partial class Rect : Shape { public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); } public override void Check(Polygon sh1, Circle sh2) { sh1.Check(this, sh2); } public override void Check(Polygon sh1, Rect sh2) { sh1.Check(this, sh2); } public override void Check(Polygon sh1, Polygon sh2) { sh1.Check(sh2, this); } } public partial class Polygon : Shape { public override void Check(Shape sh1, Shape sh2) { sh1.Check(this, sh2); } public override void Check(Circle sh1, Shape sh2) { sh2.Check(this, sh1); } public override void Check(Circle sh1, Circle sh2) { Show(sh1, sh2); } public override void Check(Rect sh1, Shape sh2) { sh2.Check(this, sh1); } public override void Check(Rect sh1, Circle sh2) { Show(sh1, sh2); } public override void Check(Rect sh1, Rect sh2) { Show(sh1, sh2); } public override void Check(Polygon sh1, Shape sh2) { sh2.Check(sh1, this); } public override void Check(Polygon sh1, Circle sh2) { Show(sh1, sh2); } public override void Check(Polygon sh1, Rect sh2) { Show(sh1, sh2); } public override void Check(Polygon sh1, Polygon sh2) { Show(sh1, sh2); } } // Program.cs public class Test { [STAThread] public static void Main(string[] args) { List<Shape> l = new List<Shape>(); foreach (Type t in Assembly.GetExecutingAssembly().GetTypes()) if (t.IsSubclassOf(typeof(Shape))) l.Add((Shape)Activator.CreateInstance(t)); foreach (Shape s1 in l) foreach (Shape s2 in l) foreach (Shape s3 in l) Shape.Check(s1, s2, s3); } }
2次元オブジェクト(丸、四角、多角形)の衝突判定を考えてみよう。前にC++でダブルディスパッチの例を書いた。 C#でもトリプルディスパッチを上記のようにかける。特徴は、
- 2次元オブジェクトの種類が増えても、partial classを活用しているため、それまでの具象クラスのファイルは修正不要。
- 2次元オブジェクトの種類が増えても、実行速度は不変。
- ダブルでディスパッチでも、それ以上でも同様にかける。
- Checkを再度呼び出す処理は、自動で生成可能。ただし、VS2005を使えば、書くのも簡単。