I am just jumping into C# from Java on the recommendation of my uncle. The Java geometry lib seems more complete than C#’s Drawing lib, so I am working on a simple bit of porting with a small bit of added functionality to begin into C#.
However, I have run into a design issue and cannot discern which would be the better choice. To have multiple methods in the abstract base class that take concrete datatypes OR to have less methods that take the abstract base as its argument?
public abstract bool isOverlapping(GeometricObject2D o) {}
OR
public abstract bool isOverlapping(Rectangle2D rect) {}
public abstract bool isOverlapping(Circle2D circ) {}
etc...
The argument I am having in my head tells me concrete arguments prevent logic errors, BUT, I have been taught to always use abstract datatypes if the use fits.
If you want to put the operation in the base class, use the abstract type. You don’t want to have to modify the base class every time you decide to add a new subclass.
An alternative is to use something like the visitor pattern and have each concrete class dispatch in turn to the visitor. An intersection visitor would then contain all the knowledge of how to compute the intersection of each pair of object types.
Here’s how the visitor pattern can be used for this. (I’ll use Java syntax since I’m not a C# programmer). First, using the visitor pattern here is more complicated than the usual case because you have to modify the operation based on the types of two arguments. In effect, you need triple dispatch. Languages like Clojure support this directly, but in Java (and probably C#) you need to simulate triple dispatch by using two levels of visitor. It’s ugly, but the great benefits are that it keeps your geometry hierarchy clean and maintainable, and it centralizes all intersection logic in one compilation unit.