Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I limit overriding in a hierarchy?

This is an example, I'm just curious as to how it would be achieved.

I want to enable only subclasses of Animal to be able to set the number of legs that they have, but I still want them to be able to set their own colour. Therefore, I want to restrict classes further down the hierarchy from then altering this Legs property.

public abstract class Animal
{
    public string Colour { get; protected set; }
    public int Legs { get; protected set; }

    public abstract string Speak();
}

public class Dog : Animal
{
    public Dog()
    {
        Legs = 4;
    }

    public override string Speak()
    {
        return "Woof";
    }
}

public sealed class Springer : Dog
{
    public Springer()
    {
        Colour = "Liver and White";
    }
}

public sealed class Chihuahua : Dog
{
    public Chihuahua()
    {
        Colour = "White";
    }

    public override string Speak()
    {
        return "*annoying* YAP!";
    }
}

For example, I want to eliminate this kind of subclass:

public sealed class Dalmatian : Dog
{
    public Dalmatian()
    {
        Legs = 20;
        Colour = "Black and White";
    }
}

How would this be achieved?

I'm aware that I could stop overriding in a subclass by sealing the implementation of a function in the parent class. I tried this with the Legs property but I couldn't get it to work.

Thanks

like image 411
fletcher Avatar asked Jul 27 '10 14:07

fletcher


4 Answers

In part, this goes against OO principles. Your superclass Animal makes available a contract which includes the set/get for Legs. You then want a subclass to be able to restrict that interface to disallow set Legs. Since subclassing provides an "is-a" relationship, restricting the interface goes against this, which would mean that subclasses would not be true subtypes, since the set Legs methods is not present.

I would remove the setter for the Legs property from Animal, since that is an implementation detail. Instead simply have an abstract getter. Subclasses can then decide how best to implement this, either by returning a hard-coded value or by using a field to store the value.

like image 126
mdma Avatar answered Sep 29 '22 12:09

mdma


Rather than having the Legs a field of the abstract class, you should make it a property only (remove the setter), and make it abstract.

In Animal

public abstract int Legs { get; }

In Dog

public override sealed int Legs { get { return 4; } }
like image 45
Mark H Avatar answered Sep 29 '22 13:09

Mark H


In Java, you'd make the getters and setters final methods, so they couldn't be overridden. In C#, I believe the keyword you want is "sealed"; you'd seal the method, but not the entire subclass.

You'd make the variable itself private, so subclasses would have to use a getter/setter to access the variable.

like image 39
Dean J Avatar answered Sep 29 '22 13:09

Dean J


class Quadruped : Animal
{
    public int Legs { get {return 4;} }
}

class Dog : Quadruped
{
    ...
}

?

I guess then you'd never want to classify an octopus as a quadruped.

I think that if you have this sort of problem, you need to re-arrange the hierarchy.

like image 26
izb Avatar answered Sep 29 '22 12:09

izb