开发者

Interface bloat needs trimming

Sorry about the bad title, I couldn't think of a more descriptive one.

The Shape ADT I have is steadily getting bigger and more bloated, specifically due to this section of the interface:

 
class Shape() {
    //...
    virtual bool Intersects(const Point& point) const =0;
    virtual bool Intersects(const Line& line) const =0;
    vi开发者_JAVA技巧rtual bool Intersects(const Line& line, bool isInfinite) const =0;
    virtual bool Intersects(const Rectangle& rectangle) const =0;
    virtual bool Intersects(const Circle& circle) const =0;
    virtual bool Intersects(const Ellipse& ellipse) const =0;
    virtual bool Intersects(const Triangle& triangle) const =0;
    virtual bool Intersects(const Arc& arc) const =0;
    //...
};
 

every new class that subclasses Shape has to be added into the interface. This is getting old fast. I remember reading somewhere that there was a design pattern to fix the issue. Templates are out of the question: each shape has its own unique way of detecting an intersection with different objects, as such, its no better than what is currently being done.


The first thing to realize that as structured, this can't help but break encapsulation. Each intersection function must know the internal workings of two different objects.

The second thing to realize is that this is an n^2 problem, or more precisely n*(n+1)/2. Each time you add a new shape, you must add an intersection function for each of the previous n shapes. Clearly this doesn't scale, which is why you asked for help.

In the real world, the way to handle this problem is to come up with a smaller number of classes that can act as a superset of some of the shapes. For example, your Point, Line, Rectangle, and Triangle could all be expressed as a collection of line segments; your Circle could be an Arc that covers 360 degrees. If exactness is not required, you could approximate every single shape as a collection of Bezier curves and have a single Intersect method that has knowledge of the collection.


The problem you are having is one of using the wrong feature for the task.

You have two objects, each of some indeterminate type, but you do know that it is over a finite set of types. You now want to call a function that will perform some operation on the two of them. And the implementation of this function will change based on pair of types; it isn't based on just one type or the other.

OOP isn't going to help you here. You need a different design for this. What you need is a list of functions that perform intersections between the various legal pairs of types. Then, you use a dispatch function to index into this table based on the two types at runtime. So you need a bit of RTTI code to get a type index or something that you can use to dispatch based on.


Point, Line, Rectangle, Circle, Ellipse, Triangle and Arc is all "Geometry" - you're missing a base class. Or is the common base class "Shape"? If so, you have even more problems (interface Shape knows about it's implementations).

I'd create a common base class and declare one virtual intersect method. You could probably use the visitor pattern to implement actual intersection logic without the base class knowing about all the different implementations.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜