gpt4 book ai didi

c# - 如何为其派生类型的每种可能组合实现基类的方法

转载 作者:可可西里 更新时间:2023-11-01 08:43:24 24 4
gpt4 key购买 nike

我有以下由多个其他类实现的 Shape 接口(interface),例如 Rectangle、Circle、Triangle ...

interface IShape{
bool IsColliding(IShape other);
}

IsColliding 方法应该检查一个 Shape 是否与另一个 Shape 发生碰撞,而不管它们的具体类型。然而,每一对形状(矩形/矩形、矩形/圆形、圆形/三角形等)都有自己的碰撞检查实现。

我正在努力为这个问题找到一个好的设计解决方案。

天真的方法是切换“其他”形状的类型以调用正确的实现:

class Rectangle : IShape{
bool IsColliding(IShape other){
if(other is Rectangle){
return CollisionHandler.CheckRectangleVsRectangle(this,(Rectangle)other);
}else if(other is Circle){
return CollisionHandler.CheckRectangleVsCircle(this,(Circle)other);
} else
// etc ...
}
}

但添加新形状意味着修改每个派生类中的方法以添加新案例。

我还想像这样调用一个独特的静态方法:

static bool IsColliding(IShape shapeA, IShape shapeB);

但即使它集中了所有内容,它也会使要执行的类型测试的数量加倍,而且我仍然必须在每个第一级“if”中添加一个新案例。

if(shapeA is Rectangle){
if(shapeB is Rectangle){
// Rectangle VS Rectangle
}else if(shapeB is Circle){
// Rectangle VS Circle
}else{
// etc ...
}
}else if(shapeA is Circle){
if(shapeB is Rectangle){
// Rectangle VS Circle
}else{
// etc ...
}
} // etc ...

那么,如何才能更好地设计它呢?

最佳答案

这里有一个使用double dispatch的想法(超越访问者模式的原理):

基本事实是碰撞函数是对称的。 IE。 IsCollision(shapeA, shapeB) = IsCollision(shapeB, shapeA)。因此,您不需要实现每个 n^2 组合(n 是形状类的数量),但只需实现其中的大约一半:

         circle  tri rect
circle x x x
tri x x
rec x

所以假设你有一个形状的顺序,每个形状都会与位于它们之前或相等的形状发生碰撞。

在此实现中,形状特定的碰撞处理被分派(dispatch)给一个名为 CollisionHandler 的对象。以下是界面(为简洁起见进行了简化):

interface IShape
{
int CollisionPrecedence { get; }
AbstractCollisionHandler CollisionHandler { get; }
void Collide(AbstractCollisionHandler handler);
}

class AbstractCollisionHandler
{
public virtual void Collides(Circle other) { throw new NotImplementedException(); }
public virtual void Collides(Rect other) { throw new NotImplementedException(); }
}

基于这些接口(interface),具体的形状类有:

class CircleCollisionHandler : AbstractCollisionHandler
{
public override void Collides(Circle other)
{
Console.WriteLine("Collision circle-circle");
}
}
class Circle : IShape
{
public int CollisionPrecedence { get { return 0; } }
public AbstractCollisionHandler CollisionHandler { get { return new CircleCollisionHandler(); } }
public void Collide(AbstractCollisionHandler handler) { handler.Collides(this); }
}

class TriCollisionHandler : AbstractCollisionHandler
{
public override void Collides(Circle other)
{
Console.WriteLine("Collision tri-circle");
}

public override void Collides(Tri other)
{
Console.WriteLine("Collision tri-tri");
}
}

class Tri : IShape
{
public int CollisionPrecedence { get { return 1; } }
public AbstractCollisionHandler CollisionHandler { get { return new TriCollisionHandler(); } }
public void Collide(AbstractCollisionHandler handler) { handler.Collides(this); }
}

调用具体碰撞函数的函数是:

static void Collides(IShape a, IShape b)
{
if (a.CollisionPrecedence >= b.CollisionPrecedence)
b.Collide(a.CollisionHandler);
else
a.Collide(b.CollisionHandler);
}

如果你现在想实现另一个形状 Rect,那么你必须做三件事:

改变 AbstractCollisionHandler 以包含矩形

abstract class AbstractCollisionHandler
{
...
public virtual void Collides(Rect other) { throw new NotImplementedException(); }
}

实现碰撞处理器

class RectCollisionHandler : AbstractCollisionHandler
{
public override void Collides(Circle other)
{
Console.WriteLine("Collision rect-circle");
}

public override void Collides(Tri other)
{
Console.WriteLine("Collision rect-tri");
}

public override void Collides(Rect other)
{
Console.WriteLine("Collision rect-rect");
}
}

并在Rect类中实现相关接口(interface)方法:

class Rect : IShape
{
public int CollisionPrecedence { get { return 2; } }
public AbstractCollisionHandler CollisionHandler { get { return new RectCollisionHandler(); } }
public void Collide(AbstractCollisionHandler handler) { handler.Collides(this); }

}

就这么简单。这是一个显示调用函数的小测试程序:

Collides(new Circle(), new Tri());
Collides(new Tri(), new Circle());
Collides(new Rect(), new Circle());

输出:

Collision tri-circle
Collision tri-circle
Collision rect-circle

关于c# - 如何为其派生类型的每种可能组合实现基类的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39317887/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com