2012-10-17

Object composition and class inheritance are both techniques hanging around forever from the early days of object oriented programming and before that in macro programming. before you decide to use one technique exclusively, or to dismiss both, consider the following questions.

What are they?

Who should use them?

When should you use each approach?

Why should you use them (or not use them)?

Which is the best?

What are they?

Class inheritance is well known in object oriented programming. Objects are created from classes. A class is a bunch of code. Assume you have some classes named example_a and example_b. If example_b is going to duplicate a lot of the code in example_a, you can start example_b from example_a with an instruction similar to example_b extends example_a. the details vary from one programming language to another. Effectively example_b starts as a copy of example_a then the code in example_b is copied over the top. Anything in example_b with the same name as something from example_a will replace the code from example_a.

Object composition

Object composition builds big sets of code from objects, not classes. Every class creates one object. When you connect two bits of code, you do it by linking the objects, not by connecting the code through inheritance or any other code oriented technique.

Who should use them?

Most specialised techniques work best when you are the main developer on a big swag of new code. If you are a contractor adding onto existing code, add your code the way the existing code is built because consistency is easier to manage and maintain than a mixed bag of styles.

Object inheritance works well in some languages but not in others. A Web developer specialising in PHP can easily use inheritance while the person that the next desk, the jQuery expert, will find inheritance useless.

A Web developer specialising in CSS and Photoshop might ignore both techniques because they rarely write any code in an object oriented language and, when they do, they want absolutely the most simple direct way of achieving hatever change they need. Long drawn out linear programming, the old spaghetti code, is easier to use when you are not writing code every day.

When should you use each approach?

Inheritance works best when most of the code from example_a is used in example_b. If example_b replaces almost everything from example_a, example_b is probably doing something different and is not related to example_a in a way where inheritance is useful. A common example is the storage of addresses. You create a class to store the simplest address in common use. You then extend the basic address with special cases. Your base address might be extended as work_address, delivery_address and international_address. The extending can be by class inheritance.

Object composition is the better choice for connecting an address to a person. Some systems define a person as a class then extend the person class through inheritance to add addresses and other attributes. The problem with inheritance is the difficulty of processing the person when extended multiple times. You might want to update the person and the international address but not the dozen other attributes added in between the person class and the international address class.

If you use object composition to build the picture of the user, you can submit updates for just the person object and the international address object without updating anything else.

Why should you use them (or not use them)?

Both techniques isolate code and reduce code duplication. You isolate sections of code to stop one part of the code trampling over the data in another part of code. Isolating code in a function is the first step and is limited in the range of data you can return from a function. An object is more flexible and is the first thing you learn after you start using functions. The next problem is extending an existing class/object without breaking what you already have.

Both object composition and class inheritance give you a way to add something today without breaking what you built and tested yesterday.

Inheritance lets you add attributes and methods to an existing class. Depending on the visibility and use of existing attributes and methods, your new class should work without breaking any existing use of the existing class. The one time you start to break stuff is when you find the methods in your new class do not work with the methods and attributes in the inherited class. You will have a strong urge to change the existing class to fit your new use but those changes will break the existing use. I know from the experience of building hundreds of applications in many languages. you will break something when you mess with an existing class.

Well, you may not break anything if you wrote the existing class because you will have designed it with expandability in mind. This synchronistic magic only happens when you have considerable experience and design the whole application, a situation where you can see future needs far enough to code each class ready for reuse across the whole application.

At this point you might want to look at object composition. Object composition leaves the existing class alone and reuses the object, not the class. Class example_a might be a user. Class example_b might be a user with an active session in your Web site. Instead of inheriting example_a into example_b, you create an object example_a to represent the user then you create an object example_b for the session and pass object example_a to object example_b.

All your existing code can continue to create example_a objects without any changes. All your new code can create example_b objects without breaking anything. The only problem is accessing something in example_a from example_b.

Assume example_a has attribute abc. Assume you are using example_b and want to access abc. How do you access abc? Some people create an attribute or method in example_b to return abc from example_a while others create attributes and methods to return example_a so you can independently access abc. This is the only protocol you have to define for your application or class and is the one place where people suddenly return to class inheritance instead of object composition.

Whichever approach you use, you will create less code compared to not using either approach, assuming you are using a programming language that supports one of the techniques.

Which is the best?

The real answer is to use both, use whatever works best for the bit of code you are about to write. Look at the code you are working with and favour the approach they use because consistency is easier in the long run. Switch to the other approach when there is a real advantage.

Ignore the fashion rubbish you were taught in school because it is probably based on a book from the 1990s when people liked to throw out the development experience built up by previous generations on the stupid assumption that a microcomputer is nothing like a mainframe. The only difference was the microcomputer was limited in hardware and now microcomputers can do everything mainframes used to do, which means they need all the things developers learned on mainframes.

In between speaking at a conference, I attended a session where a Linux kernel developer talking about a magic new problem with a spin lock stopping Linux from handling multiple requests on multiple processors. OMG, this is so new! Except that several years before that I sat in on a session where a Unix developer said almost the same thing and more than ten years before that listened to a mainframe operating system developer describe how he was on a team solving exactly the same problem on mainframes many years before talking with me. At the time the Linux developer described the magic new problem, the problem and solution were 20 to 30 years old.

A type of code inheritance was in the macro language wrapped around mainframe Assembler. As a junior nobody training, I used a type of code inheritance to to make my code work with multiple applications in multiple operating systems without modification. The language did not have classes but I could bring in and reuse code the same way most object oriented languages inherit code when you have single inheritance.

A type of object composition was also available back then. While it was not called an object, it isolated code and data in a similar way and allowed reuse in the same way. you used it in the same circumstances for the same reasons. Both options were available and the object composition composition technique was used more often only because it was easier in that language.

In fact in most languages with most debugging techniques, object composition is easier. Class inheritance makes debugging really complicated. Debugging is required less when you design everything yourself. Class inheritance is a really powerful tool you can use easily back at the start of the design process when you control how data is structured and you can split the data up into nice chunks for inheritable classes.

Class inheritance can also be easy at the end of the development phase if the original architect designed the right classes and the coders implemented the classes the right way. You can avoid the complicated reuse of object example_a in object example_b if example_a and example_b were designed to work together.

How do you decide?

Lets go back to the example of the user in example_a and the address in example_b. Does the user have an attribute of name? Probably. It is common. Does the address have an attribute of name? It should not. The address should have street_name but not name by itself. If both the user class and the address class use the same attribute of name for different data, one class cannot extend the other because the attributes will overlap.

If you control the address class, you can change name to street_name then extend user as address. If the attribute name is already defined and used in other code, the change is too difficult. This example is over simplified and is exactly the type of problem you hit when using class inheritance if someone else built the code. Avoid inheriting a class if you do not control the inheriting class and cannot change code, in the inheriting class, to fix the problems.

I ran into inheritance problems a few times and the hardest problem to fix was a case where application B inherited code from framework A but the developers of the two sets of code refused to synchronise their changes. Framework A would change the name of an attribute, or method, and the developers of application B would argue endlessly about the change then finally update application B at almost the same time as framework A issued a new update with additional changes. In that case I gave up on both open source projects, after several attempts, and used a competing product.

Object composition does not solve all the problems by itself. In the case where B uses A, it is easier to test B and A separately. You can see the data flowing from B to A then test A for that range of data. If you have a good testing system and the time, you can test every object in A to make sure it contains what B expects.

Object composition tends to fail where you have complex data types and repeating the definition of the data types across each class is a pain. You can use inheritance to replicate the complex data definitions from class to class but then use object composition to bring together all the objects when you execute the program. You define your geospacial coordinate data as example_g. Example_a inherits example_g. Example_b inherits example_g. When you run the application, example_b is composed with example_a as an input object and they share the same definition of the example_g data.

Other approaches

Drupal 7 is an example of an application where small updates can be extremely difficult because the data is buried in a huge object and the update defaults to all or nothing. Drupal starts with small objects then lets all the add-on modules, including Drupal core modules, slap heaps of other attributes into the object. The modules are then expected to extract all the data during an update and decide, attribute by attribute, if there is a change that has to be recorded back into the database. There is no option to group related data into smaller blocks of data and update only the groups with changes.

Drupal 7 does not use class inheritance or object composition. Class inheritance is something Drupal cannot currently use because the current coding style does not encourage class inheritance. Object composition fits the current coding style and is used occasionally but often in the wrong place for the wrong reasons. Drupal 7 could use a good rewrite to remove the use of objects within objects where they serve no purpose and to introduce object links where they are really needed.

The Drupal 7 problem is tackled in a number of ways in Drupal add-on modules but the best option for many of the modules, object composition, is not usable because the attributes in connected objects would not be visible to the rest of Drupal. There are places where the developers have put in the extra miles to make object to object links work with, in one case, a really good interface where things are logical, and in other cases interfaces where the links are obscure, inconsistent, and unreliable. The inconsistency is the result of the way Drupal developed. The unreliability is the result of the inconsistency plus the obscurity.

Conclusion

Be brave. Use both class inheritance and object composition but be proactive with both, experiment on your own time before billing a client for the result or betting your next pay rise on either approach.

If you want example exercises to try at home, I can supply a few in PHP.







Facebook Like

Google Plus One

Linkedin Share Button

Tweet Widget

Show more