Development

Elipse and Circle inheritance problem

Recently I’ve been listening to Coding Blocks podcast, an episode which subject was software design anti-patterns. They described one of them, which is pretty well known: the Circle-Ellipse problem.

The problem goes like this: let’s assume we’re writing a program and we’ve created IShape interface (which might have methods to calculate circumstance and area of the shape). Now we create Ellipse, which implements IShape interface and follows that with Circle class. Now since Circle is a special case of Ellipse, and every circle is an Ellipse it naturally should inherit from Ellipse.

    public interface IShape
    {
        decimal Circumstance();

        decimal Area();
    }

    public class Ellipse : IShape
    {
        public void Stretch(double x, double y)
        {
        }

        public decimal Circumstance()
        {
        }

        public decimal Area()
        {
        }
    }

    public class Circle : Ellipse
    {
    }

The obvious problem is that ellipse can be stretched, but a circle cannot. And since Circle inherits all methods from Ellipse now it also can be stretched.

Solution 1

Make stretch method return bool if an operation was performed, and check that bool after you invoke a method.

But now you have to create a lot of if-else logic around each invocation and check if you don’t have to convert types or if anything else works.

Solution 2

Make calling Stretch method throw a NotSupported exception when invoked on a circle.

I find this really annoying. If you’re unfamiliar with the domain you will have no idea why calling this method results in an exception, nor there is any way to actually work around it.

Solution 3

Make stretch don’t do anything if you invoke it on a circle.

It seems ok because it won’t create an error, but you might be baffled why you tried to transform something and nothing happened. This kind of hidden error might be even worse than an outright exception because you might not be sure why it didn’t work.

Other ideas

You could try a range of other solutions, like inverting circle-ellipse inheritance (since Ellipse provides a wider range of possibilities) or create common ancestor Rounded, which would have all operations protected and each shape would inherit only those that were required for it, however…

You could just ditch the circle.

What is an actual gain in having a separate class, that just seems more familiar but adds no real value? There is nothing that Circle can do but Ellipse can’t. You could add property IsCircle as a boolean field to Ellipse if for some calculations (or other reason) a distinction is required, but otherwise, it might be possible to avoid this problem completely.

Unless you’re able to think about some example for which it just can’t work.

Standard

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s