Dennis’s Weblog

Inheritance and Interface

Posted on: October 7, 2008

OO Principle:

Favor composition over Inheriance;

When we first learn OOP, We know Inheriance. With it, we can reuse the code by extend it. Later we know we spend much more time extent and maintain the code than reuse the code. When you use inheriance, the relationship is “Is A”, In other words, the extended object are actually a superclass object. They have the same fields and methods. With the use of these methods, we can reuse the oringinal code.

But when we would like to maintain the code and add some new functions, problems come out. Once you want to add new feature to a existed class, you should update all the existed class, and this cause a nightmare.

Since that there is a OO principle: prefer composition to inheritance.  Composition means the relationship is “HAS A”. The merit of inheriance is reuse. When we use composition we can have such a merit by contain a superclass object but not inherit it. With this contained superclass object, we can still reuse the super class code to implement and add new features to our new object.

At the same time, In C++, there is a feature: multiple inheritance. That means a class can inherit mutiple class ‘s features and reuse their code. How can we implement such a function with our language ? Yup, we can contain mutiple objects which have the features that we want to inherit, and then we can have their functions. Futhermore, if these object that we want to inherit have something common, then we  can define a interface, and all the “superclass” that we want to contain should implement this interface. And then we can use such a common interface in our inherited class to process all the “superclass”, for example, we can have add() or remove() functions which can add or remove the superclass features.(the Duck example in Head first Design patterns)

Each class know other class only the common interface, once one of them changed will not affect the other class! That’s what we said: loosely coupled OO Design Principle.

 

_________________________________________________________________________________________________

There are two pervasive software development problems that OOP evolved to solve: handling complexity and handling change.

Inheritance allows you to create a new class that is a variation on an existing (base) class, and to substitute the new derived class in any situation that originally called for the old base class. For example, if you have a class called SalesOrder, you can create a new derived class called WebSalesOrde Any existing methods that take an object of type SalesOrder can remain unchanged and will now be able to handle WebSalesOrder objects as well.

Polymorphism

Polymorphism, or substitutability, is one clear benefit of inheritance: any time you create an object from a derived class, you can use that object anywhere you can use an object from the base class. A WebSalesOrder “is a” SalesOrder, and it must be able to do everything a SalesOrder does, even if it does it in its own distinctive way.

Polymorphism is the key to many of the advantages to OOP, and, as you’ll see later in this document, it is not only available when you use inheritance, but also when you use interfaces. Polymorphism allows different kinds of objects that are all able to process a common set of messages to be used interchangeably, and to process those messages in their own ways.

Virtual Methods and Properties

Virtuality only comes into play when you override base class methods in derived classes, and it is perhaps the most magical part of inheritance. The magic is that the Microsoft .NET runtime automatically finds and runs the most specialized implementation of any method or property that is called.

For example, calling order.Confirm in the example above reaches down to the Confirm method of WebSalesOrder, where the base SalesOrder.Confirm method was overridden. However, order.Total calls the Total method of SalesOrder, because no specialized Total method was created in WebSalesOrder.

Abstract Classes and Methods

An abstract class is one that includes at least one method or property that must be overridden. For example, you could have created a SalesOrder class that didn’t implement any way of confirming an order. Knowing that different kinds of orders must be confirmed in different ways, you can specify that a class derived from SalesOrder must override the Confirm method and provide its own implementation.

Now, what if some kinds of orders need confirmation and some don’t? You could use a base SalesOrder class that doesn’t include a Confirm method and only add Confirm to those derived classes that need it. But this will create a problem: You may want to create a procedure to handle all kinds of orders and confirm those that need confirmation. How would you know which ones to confirm?

You could give the procedure a parameter of type SalesOrder, allowing all types derived from SalesOrder to be passed in. But then you would need to test for all the different confirmable types before calling the Confirm method. Furthermore, once you found an order type that was confirmable, you would need to downcast from the SalesOrder type, which does not have a Confirm method, to the derived type that does:

Public Sub ProcessOrder(order As SalesOrder)
 If TypeOf(order) Is WebSalesOrder Then
   CType(order, WebSalesOrder).Confirm
 ElseIf TypeOf(order) Is EmailSalesOrder Then
   CType(order, EmailSalesOrder).Confirm
 ' and so on

This kind of code is very hard to maintain. It forces you to modify the method any time a new type derived from SalesOrder is added to the system. That kind of coupling between old code and new code is exactly what you want to avoid.

This would be almost as bad as implementing the confirmation code in this procedure for each different kind of sales order:

If TypeOf(order) Is WebSalesOrder Then
   ' Put code here to confirm a WebSalesOrder
ElseIf TypeOf(order) Is EmailSalesOrder Then
   ' Put code here to confirm an EmailSalesOrder
' and so on

That pattern is even worse; not only must you change the procedure for every new type you create, you also no longer have each sales object handling its own confirmation, making it much harder for a programmer who needs to add a new type of sales order. How would that programmer know all the places where new code is needed to handle the new type?

Another approach would be to create an intermediate abstract type called ConfirmableSalesOrder, derived from SalesOrder, with a MustOverride method, Confirm. You derive any types that need to handle confirmation from ConfirmableSalesOrder, and derive any other types directly from SalesOrder. The procedure now only has to check whether SalesOrder objects passed in were of type ConfirmableSalesOrder, and if so, it could use that type to call the Confirm method:

If TypeOf(order) Is ConfirmableSalesOrder Then
   CType(order, ConfirmableSalesOrder).Confirm

The CType downcasting conversion is still required to get to the Confirm method. But then, through the magic of virtuality, the call automatically passes down to whichever derived class the order was created with and runs the Confirm code defined there.

So, the problem seems to be solved, but this is only a temporary solution. Have you guessed why? Suppose you next need to deal with the fact that some types of orders need a credit check. Some of the orders needing credit checks are also ones that get confirmed, but some aren’t. Now you’re in trouble.

No Multiple-Inheritance in .NET

The biggest problem with multiple-inheritance is that it allows for ambiguity when the compiler needs to find the correct implementation of a virtual method. For example, suppose that Hound and Puppy are both derived from Dog, and then BabyBasset is derived from both Hound and Puppy:

Figure 1. The problem with multiple-inheritance

Now suppose that Dog has an overridable Bark method. Hound overrides it to sound like a howl, Puppy overrides it to sound like a yelp, and BabyBasset doesn’t override Bark. If you create a BabyBasset object and call its Bark method, what will you get, a howl or a yelp?

The .NET Framework prevents these kinds of problems by mandating that a derived class can only have a single base class. This limitation also means that every class is ultimately derived from a single great-grand-daddy class, System.Object.

Creating and Implementing Interfaces

The subtleties concerning inheritance are very interesting, but what are we going to do about our sales orders that need confirmation and/or a credit-check? The answer is to use interfaces.

The problems caused by multiple inheritance of classes result from potential conflicts among the various implementations of common methods in the inheritance chain. But suppose you knew that the classes you were inheriting from were pure abstract classes with no implementation? In that case, multiple-inheritance wouldn’t cause any problems because there would be no implementations to cause conflicts. This is what interfaces provide: a way to inherit just a set of method and property specifications with no implementation to worry about and no problem inheriting from as many interfaces as you need.

Comparing Class Inheritance and Interface Implementation

The most important technical distinction between creating a derived class and implementing an interface is that a derived class can only inherit from one base class, but a class can implement any number of interfaces.

For adding those kinds of features or capabilities to a class, implementing interfaces will give you much greater flexibility.

Object Composition

When considering the creation of your own inheritance hierarchies, don’t be overly influenced by the appeal of code reuse. That alone is not a good reason to create a derived class.

Instead of using inheritance to allow a new object to make use of code from an existing object, you can instead use a technique that goes by several different names: composition, containment, aggregation, or wrapping. This is a technique that you are likely to have used in Visual Basic 6.0, where inheritance wasn’t an option.

For example, to create a WebSalesOrder class that reuses all the code in the SalesOrder class and that also adds some new twists, you declare and create an instance of a SalesOrder object in your WebSalesOrder class. You can publicly expose the internal SalesOrder, or you can keep it private.

Delegation

If SalesOrder has a Total method, your WebSalesOrder can have a Total method that simply calls into the Total method of the private SalesOrder instance. This technique of passing along method calls (or property calls) to an internal object is often called delegation, but don’t confuse it with the unrelated use of delegate objects to create callback functions and event handlers in Microsoft .NET. The events of your contained objects can be exposed in the wrapper class by declaring the contained object using the WithEvents keyword, just as in Visual Basic 6.0.

Combining Composition with Interface Implementation

The primary disadvantage of using object composition and delegation is that you don’t automatically get polymorphism the way you do with derived classes. If your WebSalesOrder object simply contains a SalesOrder object, rather than being derived from one, then you can’t pass a WebSalesOrder object to a method that has a parameter of type SaleOrder.

You can easily work around this disadvantage by creating an ISalesOrder interface that your WebSalesOrder implements. You have the option of delegating to the methods and properties of the contained SalesOrder object. Or, as needed, WebSalesOrder can independently implement some of the methods and properties in the interface instead of delegating to the SalesOrder object. This is similar to overriding in derived classes.

By combining object composition and delegation with interface implementation, you get code reuse and polymorphism without the design headaches of inheritance. For this reason, consider this as your first choice when you need to extend or specialize the functionality of classes.

The second reference:

    http://msdn.microsoft.com/en-us/library/ms973861.aspx

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: