Alternative Inheritance Paradigms in Object-Oriented Design

Architecturecdesigndesign-patternsobject-oriented

My apologies if a variation of this question has been asked before, but due to its nature it is hard to search for.

I am having a discussion with a colleague about object-oriented design, and it basically comes down to a choice between two different paradigms. What I had been searching Google for was a discussion between these – as I've seen both discussed.

Paradigm A

Have a small number of classes which answer a lot of public methods, many of which are not applicable unless in certain circumstances. In these cases, they throw a runtime exception.

Example: a mathematical vector class can have any number of elements. This class answers 'Cross', but returns an error if it has anything other than 3 elements.

Paradigm B

A deeper inheritance tree, with methods only appearing where they are applicable.

Example: the mathematical vector class is specialised as a 3D-vector, with only the 3D-vector answering 'Cross'. 3D vectors are a special case as there are many functions relevant to a positional vector alone (Dot, Cross, Distance, AngleTo, etc).

I'm not actually asking for opinions on the above (although clearly the second is better!) but where can I find a good discussion on this – and similar – design issues. I can find many beginners' discussions/tutorials on the subject, but I haven't had any luck finding the more in-depth articles.


Edit:

After a prompt from @JohnDibling, I'll rephrase the question (and add another Paradigm on request):

Paradigm C

Lightweight objects with a suite of functions to interpret them, and throw errors if the provided arguments weren't valid.

Example: all vectors only respond to the most basic requests, and a series of functions like Size(vector), Cross(vector) do all of the work. Cross would throw a (runtime) error if an argument of the wrong size is given.

Could anyone give me specific reasons why A or C might be preferable to B, or point me to an article which discusses this issue in depth?

Best Answer

It depends on what you're trying to accomplish.

Generally when you use OOP or any other architectural technique you want to leverage the benefits that it's approach facilitates.  One of those benefits may be more reuse.  Reuse is considered good because it can reduce the overall load of code that must be reviewed,code that must be written, etc.

The OOP architectural paradigm also offers information hiding and encapsulation, important for managing and reducing complexity.  Reducing complexity in code is crucial to improving code quality and increasing overall development speed.

In my opinion, one of the best ways to refine your underlying OOP architecture is to begin to build a reference implementation.  Try to actually implement the high level functionality, at least conceptually or in pseudo code.  Doing this forces you to continue the architectural pattern you begin with the fundamental class definitions.  In this way you can get feedback from your implementation attempts about what OOP patterns are working cleanly and clearly to express your higher level functionality and which are hindering those efforts by making things more difficult by enforcing unnecessary conformance or, conversely, allowing excessive, distracting and confusing abstraction.

Known (GOF...) design pattern can help you by providing expert heuristics about which things have worked for many people over many trials.

But ultimately it is your project's requirements which will have to guide the final OOP foundation construction.

The core concept for me is whether a particular architectural approach is going to have a NET benefit or a NET loss.  If it takes longer to create a whole boatload of abstraction concepts and work out all the kinks in your inheritance hierarchy, that it would to just do a more quick and dirty approach and fix a few bugs or issues. Well, it's a judgement call.

Also, it depends on what you plan to do,  if these classes are intended to be the foundation of another 100,000 lines of OOP class hierarchy definitions, it may be time well spent to thoughtfully refine the abstractions as tightly as possible.

Related Topic