How do I limit overriding in a hierarchy?
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
Answer by izb for How do I limit overriding in a hierarchy?
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.
Answer by mdma for How do I limit overriding in a hierarchy?
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.
Answer by Dean J for How do I limit overriding in a hierarchy?
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.
Answer by Mark H for How do I limit overriding in a hierarchy?
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; } }
Answer by John M Gant for How do I limit overriding in a hierarchy?
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?
Answer by Arseny for How do I limit overriding in a hierarchy?
//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; } }
Answer by Jeff Sternal for How do I limit overriding in a hierarchy?
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.
Answer by Abel for How do I limit overriding in a hierarchy?
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 }
Answer by SaravananArumugam for How do I limit overriding in a hierarchy?
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.
Answer by supercat for How do I limit overriding in a hierarchy?
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.
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment