Oop 面向对象设计和镜像/复制方法
我在OO设计中遇到了一个问题,我在两个不同的类中得到了重复的代码。下面是发生的事情: 在这个例子中,我想检测游戏对象之间的碰撞 我有一个基本CollisionObject,它包含常用方法(如checkForCollisionWith)和扩展基类的CollisionObjectBox、CollisionObjectCircle、CollisionObjectPolygon 设计的这一部分似乎还可以,但让我烦恼的是:打电话Oop 面向对象设计和镜像/复制方法,oop,collision-detection,Oop,Collision Detection,我在OO设计中遇到了一个问题,我在两个不同的类中得到了重复的代码。下面是发生的事情: 在这个例子中,我想检测游戏对象之间的碰撞 我有一个基本CollisionObject,它包含常用方法(如checkForCollisionWith)和扩展基类的CollisionObjectBox、CollisionObjectCircle、CollisionObjectPolygon 设计的这一部分似乎还可以,但让我烦恼的是:打电话 aCircle checkForCollisionWith: aBox 将
aCircle checkForCollisionWith: aBox
将在circle子类内执行圆与长方体碰撞检查。反过来说
aBox checkForCollisionWith: aCircle
将在box子类内执行box vs circle碰撞检查
这里的问题是圆与框的冲突代码是重复的,因为它同时存在于Box和Circle类中。有没有办法避免这种情况,或者我处理这个问题的方式不对?现在,我倾向于使用一个包含所有重复代码的helper类,并从aCircle和aBox对象调用它以避免重复。不过,我很好奇是否有更优雅的面向对象解决方案。也许您可以拥有一个碰撞对象,其中包含测试不同类型碰撞的方法。这些方法可以返回包含碰撞点和其他必要信息的其他对象。所需的内容称为 多分派或多方法是某些面向对象编程语言的特性,在这些语言中,函数或方法可以基于其多个参数的运行时(动态)类型进行动态分派 这可以在主线OOP语言中进行模拟,如果使用Common Lisp,也可以直接使用它 Wikipedia文章中的Java示例甚至处理了您的确切问题,即冲突检测 以下是我们“现代”语言中的假象:
abstract class CollisionObject {
public abstract Collision CheckForCollisionWith(CollisionObject other);
}
class Box : CollisionObject {
public override Collision CheckForCollisionWith(CollisionObject other) {
if (other is Sphere) {
return Collision.BetweenBoxSphere(this, (Sphere)other);
}
}
}
class Sphere : CollisionObject {
public override Collision CheckForCollisionWith(CollisionObject other) {
if (other is Box) {
return Collision.BetweenBoxSphere((Box)other, this);
}
}
}
class Collision {
public static Collision BetweenBoxSphere(Box b, Sphere s) { ... }
}
以下是Common Lisp中的示例:
(defmethod check-for-collision-with ((x box) (y sphere))
(box-sphere-collision x y))
(defmethod check-for-collision-with ((x sphere) (y box))
(box-sphere-collision y x))
(defun box-sphere-collision (box sphere)
...)
您应该使用checkForCollisionWith:aCollisionObject,因为您的所有对象都在扩展CollisionObject,所以您可以将所有公共逻辑放在那里
或者,您可以使用在不同的类之间共享公共逻辑。您没有说明您使用的是什么语言,因此我假定它类似于Java或C 在这种情况下,多方法是理想的解决方案,但大多数语言不支持它们。模仿它们的通常方法是使用访问者模式的一些变体——请参阅任何关于设计模式的好书
或者,使用一个单独的CollisionDetection类来检查对象对之间的碰撞,如果两个对象发生碰撞,则会调用对象上的相应方法,例如bomb.explode()和player.die()。该类可以有一个大的查找表,其中每一行和每一列都有一个对象类型,并且条目提供了调用这两个对象的方法。这是OO开发中的一个典型陷阱。我也曾试图以这种方式解决碰撞问题,结果惨败 这是一个所有权问题。Box类真的拥有与circle的冲突逻辑吗?为什么不反过来呢?结果是代码重复或将冲突代码从圆圈委派到方框。两者都不干净。双重分派不能解决这个问题-所有权的问题是一样的
因此,您是对的-您需要解决特定冲突的第三方函数/方法,以及为两个发生冲突的对象选择正确函数的机制(这里可以使用双重分派,但如果冲突原语的数量有限,则可能2D函子数组是更快的解决方案,代码更少) 第一个选项:使碰撞具有方向性。例如,如果长方体是静止的,它不会检查自身与任何其他对象的碰撞;但移动的圆检查与长方体(和其他静止对象)的碰撞。这是不直观的,因为我们一生都被教导“平等和相反的反应”。陷阱:移动对象会复制与其他移动对象的碰撞
第二个选项:给每个对象一个唯一的ID号。在碰撞检查方法中,仅当第一个参数/对象的ID低于第二个参数时,才检查碰撞 假设框的id=2,圆的id=5。然后执行“box与圆圈碰撞”,因为box.id
-(BOOL) intersectsWithRectangle:(Rectangle*) aRectangle
{
return CircleAndRectangleCollision(self, aRectangle);
}
当然,它不会攻击双重分派的耦合问题,但至少它避免了代码重复这似乎很难维护,对于从碰撞对象派生的每个类,您必须在所有其他派生类中添加一个新的
checkForCollisionWithX
。这绝对很难维护。我从来没有说过这是用于碰撞检测的正确技术。实际上,代码应该自动构造冲突分派矩阵。然后,应通过该矩阵处理冲突操作。你编写一次矩阵生成器,它使用反射,之后一切都运行得又好又快。Objective-C。不过,我假设Java或C#的问题是一样的。哦,嗯。也许我解决了一个与你所说的不同的问题。为了解决您的问题,我想我应该使用泛型(java)或模板方法(c++)。
-(BOOL) intersectsWithCircle:(Circle*) aCircle
{
return CircleAndRectangleCollision(aCircle, self);
}
-(BOOL) intersectsWithRectangle:(Rectangle*) aRectangle
{
return CircleAndRectangleCollision(self, aRectangle);
}