views:

165

answers:

8

If I have an abstract class and derived classes of that class, am I correct that, according to good and practical design practice, that the derived classes should not provide extra public methods (they should only implement abstract classes and optionally override parent methods)?

Furthermore, is it acceptable practice to have a different constructor method signature for each derived class?

+2  A: 

It's perfectly acceptable to add additional public methods to your derived classes. It's also perfectly acceptable to give them different contructors. (In fact, this is quite common.)

Peter Ruderman
A: 

the derived classes should not provide extra public methods

Can a dog do things that an animal can't?

Furthermore, is it acceptable practice to have a different constructor method signature for each derived class?

There's no problem here. Derived types are not required to match constructor signatures of their siblings or parents.

David B
To answer yr question, Yes A Dog CAN do things that some animals can't do... Like Bark, Bite, Run, Shed, Jump, etc... Worms are Animals, (they're not plants) - and a worm cannot do any of those things...
Charles Bretana
+4  A: 

Personally, I see no problem with either.

As for extra public methods on derived classes:

There is limited usefulness in this, in many cases. The extra methods will not be usable when the class has been cast or set to an reference to the base class, which severely limits usefulness of this practice. That being said, there isn't anything particularly wrong with this approach. Subclasses are meant to add specific behavior - sometimes, in a class hierarchy, there is new behavior in a subclass that isn't appropriate for the base class. If the subclass is going to be used frequently on its own, it seems perfectly reasonable for the extra behavior to be modeled in the methods.

As for constructor signatures -

I see no problem with this either. Subclasses often need more information to be put into a usable state than the abstract class. That being said, I typically make sure to implement every constructor in the base class, plus add the new parameters required for the subclass.

That being said:

Unless there is good reason, I'd avoid having a subclass constructor with fewer parameters than the base class ... why would I be able to specify something on a more generic case and not the specific case? I find that it's usually confusing when subclasses have completely different construction options than their base classes.

Reed Copsey
if you're constructing an object from a factory, say, then am I right that there shouldn't be extra public methods? Shouldn't the calling code, in the case of a factory, know what methods to expect to have?
Chad Johnson
It depends - even if you're constructing from a factory, the factory will need to know the compile-time type of the object (in order to call the appropriate constructor). It can "know" about the extra parameters. In this case, though, it really just depends on the scenario, how it's going to be used, etc.
Reed Copsey
+2  A: 

This is the beauty of derived classes.

While a Pen class might have a write() function, a RetractablePen class which extends Pen might also have a retractPoint() function.

When you extend a class it means -- literally -- extending the functionality of it.

Zack
If you're constructing an object from a factory, say, then am I right that there shouldn't be extra public methods? Shouldn't the calling code, in the case of a factory, know what methods to expect to have?
Chad Johnson
If you're constructing it from a factory, then you are probably using polymorphism and looking at the class as if it's just its parent. In that case, you wouldn't have access to the methods defined in the child class unless you checked for instanceof and cast it.
Zack
+1  A: 

No, it's perfectly reasonable (and sometimes very necessary by design) to add additional public methods. Consider the (completely contrived) situation of a Shape abstract base class that has a Location member and a Size method. When you derive Polygon from Shape, for example, you may want to add a public method called GetNumberOfSides(), for example; but you don't want to have that when you derive Circle from Shape.

In the same way, the derived types may have very different construction requirements; it's not really possible to know what all the requirements may be when defining the abstract base class, so feel free to have differing signatures. Just because your dervied types will be polymorphic to the abstract base class doesn't mean that that base class imposes strict limitations on how you can implement the abstractions defined in that base class; you're free to pretty much do it however you want.

McWafflestix
+2  A: 

It's fine in general.

What you want to avoid is using the specific in the generic. i.e.

foreach(Animal a in myFarm.Animals)
{
    a.Feed();
    // this is a bit grim
    if( a is Horse )
    {
       ((Horse)a).CleanStable();
    }
}

So it's not the act of adding the public method but rather where you call them from.

Quibblesome
I want a horse that cleans its own stable! Where can I get one? ;)
Reed Copsey
Yeah... I know... i'm writing during build time so I don't have time to be as pedantic as I usually am... :(... it'll do.
Quibblesome
A: 

It is not only acceptable, it is often necessary for the constructors to be different. For example, if we have an (immutable) Rectangle class and extend it with an (immutable) Square, the constructor of Square should be (to use Java for the moment)

public Square(double size)

while the constructor of Rectangle would be

public Rectangle(double width, double height)

What does need to happen is that the subclass constructor should call some appropriate superclass constructor.

As to extra public methods, it may depend on the use. For the Square case, I would not add any extra methods. In Java, however, there is a subclass PrintWriter of Writer whose purpose is to add some convenience methods. In this case I think it okay (Java certainly has some bad examples but I don't think this is one of them). I would also expect the possibility of some extra methods for container/subpart types.

What you shouldn't do is change the super classes methods in a way that violates the expectations of the super class.

Kathy Van Stone
+1  A: 

If you respect the Liskov substitution principle, you can do what you want.

Of course, add a method to a derived class doesn't violate the principle at all.

akappa