如果要将操作放在基类中,请使用抽象类型。您不希望每次决定添加新子类时都必须修改基类。
另一种方法是使用访问者模式之类的东西,并让每个具体类依次分派给访问者。然后,一个交集访问者将包含有关如何计算每对对象类型的交集的所有知识。
以下是访问者模式如何用于此目的。(我将使用 Java 语法,因为我不是 C# 程序员)。首先,这里使用访问者模式比通常情况更复杂,因为您必须根据两个参数的类型修改操作。实际上,您需要三重调度。Clojure 等语言直接支持这一点,但在 Java(可能还有 C#)中,您需要通过使用两个访问者级别来模拟三重调度。它很丑,但最大的好处是它可以保持几何层次结构的清洁和可维护性,并将所有交集逻辑集中在一个编译单元中。
public interface IGeometry {
void accept(IGeometryVisitor visitor);
}
public interface IGeometryVisitor {
void visitCircle2D(Circle2D circle);
void visitBox2D(Box2D box);
// a method for each concrete type
}
public class Circle2D implements IGeometry {
public void accept(IGeometryVisitor visitor) {
visitor.visitCircle2D(this);
}
}
public class Box2D implements IGeometry {
public void accept(IGeometryVisitor visitor) {
visitor.visitBox2D(this);
}
}
public class IntersectionVisitor implements IGeometryVisitor {
private boolean mResult;
private IGeometry mGeometry2;
public static boolean isOverlapping(IGeometry geometry1, IGeometry geometry2) {
return new IntersectionVisitor(geometry1, geometry2).mResult;
}
private IntersectionVisitor(IGeometry geometry1, IGeometry geometry2) {
mGeometry2 = geometry2;
// now start the process
mGeometry1.accept(this);
}
public void visitCircle2D(Circle2D circle) {
mGeometry2.accept(new Circle2DIntersector(circle));
}
private class Circle2DIntersector implements IGeometryVisitor {
private Circle2D mCircle;
Circle2DIntersector(Circle2D circle) {
mCircle = circle;
}
public void visitCircle2D(Circle2D circle) {
mResult = isOverlapping(mCircle, circle);
}
public void visitBox2D(Box2D box) {
mResult = isOverlapping(mCircle, box);
}
}
private class Box2DIntersector implements IGeometryVisitor {
private Box2D mBox;
Box2DIntersector(Box2D box) {
mBox = box;
}
public void visitCircle2D(Circle2D circle) {
mResult = isOverlapping(circle, mBox);
}
public void visitBox2D(Box2D box) {
mResult = isOverlapping(mBox, box);
}
}
// static methods to compute overlap of concrete types
// For N concrete types there will be N*(N+1)/2 methods
public static boolean isOverlapping(Circle2D circle1, Circle2D circle2) {
return /* intersection of 2 circles */;
}
public static boolean isOverlapping(Circle2D circle, Box2D box) {
return . . .;
}
public static boolean isOverlapping(Box2D box1, Box2D box2) {
return . . .;
}
}