views:

271

answers:

10

Hi,

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

+4  A: 
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.

izb
Note that this isn't using language constructs to achieve the limitation, its inserting another type into the heirarchy that specifies Legs without allowing it to be overridden. Its still possible that someone can hide the member using the `new` operator though.
Adam
+11  A: 

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.

mdma
this triggered my curiosity: *"against OO principles"*. Technically it is not, but it depends on the implementation and a language must support it. Suppose you have contracts, as with Spec#, this is very OO (many consider DBC part of proper/pure OO) and can be done without loosing inheritance "is-a" relationships (expanded with example, see my answer).
Abel
@mdma - Care to provide an example? I'd definitely want a Legs getter in the animal class, so I can compare how many legs each abstract animal has got!
fletcher
Just a thought, apparently DBC is not even needed, use `sealed` on a member as in Dean J's answer. And it still won't break the inheritance hierarchy.
Abel
Animals have legs. Subclasses of animals have limited numbers of legs, but still have legs. That's what the "sealed" keyword is in C# for, and "final" pops up in Java for as well.
Dean J
@Abel - I don't mean DBC - I mean contract in the sense of a code interface, what methods are valid for calling etc.
mdma
@Dean J - sealed would work to restrict overriding the Legs getter, although you still need to remove the setter from the base class, which is the crux of my suggestion, since that is an implementation detail.
mdma
Or, to be explicitly OOP, you'd have Animals, AnimalsWithLegs, Quadripeds, Dogs as the four level class hierarchy. Unfortunately, since we don't have multiple inheritance, perhaps "Legs" should be in an interface, implemented by Dogs or Quadripeds? At some point, we lose pure OOP, and enter the real world of less-than-standardized data.
Dean J
i agree with @mdma: http://en.wikipedia.org/wiki/Liskov_substitution_principle
OXMO456
@OXMO456: you link to the Liskov principle, but all of us (afaict) have recognized that the settor should be hidden. LSP clearly shows, even in relation to DBC (which may violate some LSP principles and imo correctly so), that this is allowed for read-only properties. Thus, in this scenario, there's no violation of what OO rule whatsoever, be it Meyer, America, Hjelsberg, Liskov or Stroustrup's.
Abel
@Abel: i am lost... : )
OXMO456
+5  A: 

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.

Dean J
+1 just tried sealing methods and properties and this works, derived classes cannot override sealed members. Learn something new every day :-)
Adam
I guess that makes all the *"this is not OO"* babble rather void, is it not?
Abel
@Dean - I mentioned this in my question, but couldn't get it to work. Do you have an example?
fletcher
@fletcher: This site seems to have the relevant example: http://www.csharpkey.com/csharp/classes/sealed.htm
Dean J
@fletcher / @Dean: I took the liberty to do so, see the second half, after my DBC story, here: http://stackoverflow.com/questions/3344399/how-do-i-limit-overriding-in-a-heirarchy/3344784#3344784
Abel
or check out that link of Dean... (same instant we posted)
Abel
@fletcher: as an added note, you could make Animal, Quadriped, and Dog the three levels, and use "sealed" at the Quadriped level, if you're so inclined.
Dean J
+8  A: 

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; } }
Mark H
A: 

You might also think about what would happen if someone created a variable or parameter or type Animal and then tried to set its Legs property. Would you throw a specific exception if it was one of the subclasses that doesn't allow its legs to be set?

For example.

public void SpeedUpMyAnimal(Animal animal) {
    animal.Legs *= 2;
}

If Animal.Legs is a public property, I have every reason to believe this will work. But what if the caller passes in a dog?

John M Gant
The setter is protected, so this isn't possible.
siride
+1  A: 
//overload Leg property in Dog class and make set as private
public abstract class Animal
{
    public string Colour { get; protected set; }
    private int legs;
    public int Legs
    {
        get { return legs; }
        protected set { legs = value; }
    }

    //public int Legs { get; protected set; }

    public abstract string Speak();
}
public class Dog : Animal
{
    public int Legs
    {
        get { return base.Legs; }

        private set { base.Legs = value; }
    }
    public Dog()
    {
        Legs = 4;
    }
}
Arseny
+4  A: 

Your question implies that these classes represent ideal animals rather than actual animal instances - after all, individual animals will have a variable number of legs.

If that's the case, you don't really want a setter for Legs in the first place. The setter is a design error, since the semantics are wrong: no caller, including subclasses, should be able to set the number of legs at an arbitrary time.

Instead, demand the number of legs in a protected Animal constructor (and probably colour as well):

public abstract class Animal {
    protected Animal(int legs) {
        this.legs = legs;
    }
}

public class Dog: Animal {     
    public Dog(): base(4) {}
}

If you later decide that Dog subclasses need to be able set this after all, you can just add a new constructor that allows it.

Jeff Sternal
+1 good thinking to use base() for this purpose and the often criticized lack of ctor inheritance, which turns out a feature in this case.
Abel
@Jeff - Eh? There isn't a public setter for Legs
fletcher
@fletcher - thanks, that was sloppy of me. I really meant 'any setter at all' and I've updated my answer accordingly.
Jeff Sternal
+1  A: 

Basically, this cannot be done using C#, as has been said by several posts in this thread. It has been argued that this is not proper OO, but I beg to disagree. For ease of reference, if you have it handy, check page 464+ of OOSC. The term to be used here is Invariant inheritance. The example given is a Rectangle (always four sides), inheriting from Polygon (any amount of sides larger then 2).

The rule is simple, quote:

The invariant property of a class is the boolean and of the assertions appearing in it invariant clause and of the invariant properties of its parents, if any.

Bertrand Meyer uses Design By Contract. To a lesser extend this is available to C# as well. With .NET 4.0, it has become available through Spec#.

About the argument that this is not proper OO: the argument is correct (preventing inheritance down the chain defies the contract), but without preventing inheritance, but adding restrictions on the values by using invariant clauses, the OO paradigm is saved and the inheritance chain remains intact. Something like this:

abstract class Animal
{
    public abstract Legs { get; }
}

class Dog : Animal
{
    public Dog { } 

    [InvariantMaximum(4), InvariantMinimum(4)]
    public override Legs { get { return 4; } }
}

class Labrador : Dog
{
    public override Legs { get { return 5; } }    // compiler error
}

class Chihuahua: Dog
{
    public override Legs { get { return 4; } }    // OK
}

 

Edit (solution with sealed, a follow-up on this)

As requested in one of the threads, here's a little example that works with sealing off the further inheriting of a member (something many here considered a breach of OO, while the language designers clearly understood that it isn't):

public abstract class Animal
{
    public abstract int Legs {get;}
}

public class Dog : Animal
{
    public sealed override int Legs {get { return 4; } }
}

public class Labrador : Dog
{
    public override int Legs { get; }    // compiler error
}
Abel
With regard to Square vs Rectangle vs Polygon, if shape types are abstract and don't specify any means of change, then Square is indeed a special type of rectangle, which is indeed a special type of polygon. An editableSquare is a special type of square, and thus a special type of polygon, but neither is a type of editablePolygon unless contract for the latter type allows a shape to restrict certain types of changes.
supercat
@supercat, interesting reasoning. In DBC, a child may be more restrictive than a parent, so yes, it allows to restrict from the more admissable polygon. What I meant is that a Polygon is without restrictions (any amount of `sides > 2`), that Rectangle inherits from Polygon and adds to this restriction (`sides == 4`). Now Square comes in and inherits from Rectangle. It has no choice but to accept (`sides == 4`). Maybe I should've placed Trapezium between Polygon and Rectangle for more clarity.
Abel
@Abel: I think the issue is covariance versus contravariance. A method which expects to retrieve an arbitrary quadrilateral from a passed-in object can deal with a square, but not an arbitrary polygon. A method which expects to store an arbitrary quadrilateral into a passed-in object can use an arbitrary-polygon holder, but not a square-only holder.
supercat
@Abel: Is there any way for a class to define distinct 'override' and 'new' (I think those are the terms for VB's 'Overrides' and 'Shadows') versions of a property? For example, if an abstract class defines a readonly property, is it possible for a concrete class to both override the readonly property and create a new read-write property? It's possible to achieve that result using an intervening class, but that seems silly and icky.
supercat
A: 

In the subclasses of Animal, make the set accessor of Leg property a private. [Note: In Animal Class Leg property has to be made virtual.]

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

        public abstract string Speak();
    }

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

        public override int Legs
        {
            get
            {
                return base.Legs;
            }
            private set
            {
                base.Legs = value;
            }
        }

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

This will stop any derivative of Dog from setting Leg property.

SaravananArumugam
I don't think this is right, access modifiers cannot be changed when overriding. Surely this wouldn't even compile?
fletcher
A: 

The proper approach as noted is to make the number of legs an abstract read-only property. To make dogs whose leg count can't be overridden, I think it's necessary to create an intermediate-level class whose purpose is to define an implementation for the NumberOfLegs property, and then define the Dog class with a public NumberOfLegs function that shadows the base class property. Any effort to override the number of legs would be directed at the shadow property, so the original could no longer be overridden.

It would be nicer if one could define distinct Overrides and Shadows implementations for the same property in the same scope (with the Overrides one only being used when the property is accessed in the base class) but I don't know any way to do that.

supercat