I have designed a small library for work that consists of a few exposed classes. These can basically be thought of as a server class and client class. But now that I am writing all the test cases and examples, I am questioning myself on whether the classes should be used in a class or inherited.

I know about the composition over inheritance theology but at the same time, the OOP basics pop into my head: has-a and is-a relationships.

My main question is which makes more sense and which would make it easier for the programmers that use my library?

I have already ready numerous topics on SO and Programmers regarding this topic, none really target my question though:

  • Are you struggline to write the unit tests for these because of the structure or do you just not like how the tests look? Are the unit tests hinting at a possible re-structuring or better arch which is often what TDD can resolve? – dreza Jul 14 '12 at 22:56
  • To what deity should I pray? To the one that best fits your needs for a given situation (this rules out deities that deny the existence of others). – bitmask Jul 14 '12 at 23:10
  • 1
    This mantra needs to be considered along with the other SOLID principles. It cannot be applied in isolation. The answer will depend on how well your library follows the SOLID principles. Finally, "has-a" and "is-a" is only meant to get learners up-to-speed with OOP. For a proficient OOP programmer, Liskov, i.e. "behaves-like" and "can-do-this-way" is the only thing that matters. – rwong Jul 15 '12 at 1:34
  • 1
    How can we possibly help you make design decisions without knowing what's being designed. You don't choose between composition, inheritance, and other options based on some religious belief (or you shouldn't, at any rate). You look at the things you're modeling and your design goals and try to create a coherent solution. – Caleb Jul 16 '12 at 16:46

In the first place, any class you do write should be inheritable/extendable. C# seems to seal all its system classes and so causes me no end of trouble. Inheritence is tricky, particularly when the superclass programmer doesn't know what the subclass programmer will need and the subclasser can't modify the superclass. (And in some cases cann't even look at the superclass's code.) But inheritance can give your end users a lot of power for very little effort on their part.

But otherwise, I'd go with composition. I frequently start with a base class, extend it in all directions, then realize the base class should be an interface. If it's all in my code, this is no problem, but people using your library are going to be stuck with your choice. In Java I've ended up with two classes that look identical as far as my needs are concerned. If I could make each of them implement my own simple interface (by adding "extends myInterface"--they've both already got the methods) I'd be all set, but I have to treat them as distinct, unrelated classes.

The best idea might be to provide good interfaces and default implementations so the end users can do whatever they want. I guess my point is that your library's users should be the ones to make the composition vs. inheritance decision; your job is to give them the option.

  • 1
    There's a strong argument to be made that everything should be sealed by default. An inheritable class is effectively exposing an API interface. If they can't guarantee that'll remain constant and work, they shouldn't do it. Like you said - "Inheritance is tricky". – Chris Gwinn Jul 16 '12 at 19:03
  • Agreeing with @ChrisGwinn that the "built-in" implementations should be sealed. In fact, it is hard to prevent bugs from being "injected" by a misbehaving subclass. Having a set of sealed implementations provide a guaranteed level of correctness to the library users who do not need advanced extensions. The inheritable implementations should be provided in an extension (companion) package, preferably with full source code, so that advanced users can know how to implement their own. In both cases, "interface" should include both the language's interface declaration, and the behavior/contract. – rwong Jul 20 '12 at 6:28
  • 1
    @rwong: I agree with most of what you say. However, despite a lot of misuse, inheritance underpins OO languages. I complain about C#, but most C# classes are not sealed, and .NET wouldn't be of any use if they were. I've always found that library authors have a much more limited view of their class's possibilities than library user's do, and it seems a shame to hogtie the users. I think authors should do their best to make their classes inheritance-safe, but the users have to take full repsonsibility for any subclassing problems/disasters. (And the source code should be available!) – RalphChapin Jul 20 '12 at 16:00

Programmers should favor composition over inheritance in OO languages, period. Unless your library has a compelling reason to make forced inheritance more natural/effective, then you should assume that people will consume your library via composition.

Especially as a library writer since changing a class that is being inherited will cause more failure (in general) than one that is being composed.

  • 2
    -1 for "period." Choosing one or the other is a design decision, and you can't make a design decision without knowing what you're trying to design. I'm certainly in favor of composition when it's appropriate, but a blanket recommendation in favor of composition is no more helpful than a blanket recommendation in favor of inheritance. – Caleb Jul 16 '12 at 16:50
  • @caleb - of course, that's why it's favor rather than any of the other more binrary terms that could be used there. The emphesis was added because the OP has a number of other questions that they think do not apply to their question, which is (imo) incorrect. – Telastyn Jul 16 '12 at 16:58
  • I think you miss my point. The question is akin to "Should I use screws or nails?" It's impossible to choose without some context. Your answer is like saying: "You should favor screws because they hold better." Well, yes, screws do hold better, but that doesn't necessarily mean that one should prefer screws: you must consider the application. Indeed, the fact that the OP is trying to decide between composition and inheritance for an entire library is silly; it's very common to use both. – Caleb Jul 16 '12 at 17:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.