views:

68

answers:

3

Hi there.

I have a few questions for you wise people involving OO design with Interfaces and abstract base classes. Consider the following scenario:

I have an abstract bass class "DataObjectBase" and a derived class "UserDataObject." I also have an interface "IDataObject." The interface of course exposes all of the public methods and properties that my Data Objects must expose, and you can probably guess that the abstract base implements the methods and properties common to all Data Objects.

My question is, if the abstract bass class DataObjectBase implements everything specified in the interface IDataObject, should the interface be declared on the base class, or on the derived classes(s)?

In C# interfaces declared on the base class are implicity applied to the derived classes, but is this the best practice? It seems to me that implementing the interface on the base class makes it less obvious that the derived class implements the interface, but then again requires the Interface to be specified for each derived class.

Additionally, if the base class was NOT abstract, would the reccomendation change?

A second sub-question: If the base class implements all of the methods/properties of the IDataObject interface, is the interface even needed? The base class typename can simply be used in place of the interface name, ie:

private DataObjectBase _dataObject;
private IDataObject _dataObject;

In the above example (where again the base implements everything exposed by the interface) both can be assigned the same derived types. Personally I always use the interface in these situations, but I am intrested in hearing peoples thoughts.

Thanks in advance.

+1  A: 

If your user classes will always inherit from one base class, then you don't need the interface. If there is a possibility that you will have classes that match the interface but are not derived from the base class, then use the interface.

As for the interface being hidden in the base class and hence not immediately visible in the user class, this is normal and can be dealt withg by the compiler. This is also where good naming conventions come in - your UserDataObject has a name that matches IDataObject, as does DataObjectBase. You could add a comment to the class file that says it inherits from IDataObject, but it will be visible that it inherits from DataObjectBase, which in turn looks like it inherits from IDataObject by its name.

ck
+1  A: 

My way of thinking about such problems is to consider the different people reading the code, the "roles" if you like. Also consider the overall maintainability of the system.

First there is some code expecting to use the Interface. It's written in terms of the interface, the author has (should have) no interest in the implementation. That's why we provide the Interface class. From that perspective the Abstract Base Class is just one of many possible implementation hierarchies. Don't tell this role about implementation details. Keep the Interface.

Then we have the role who is designing an implementation. They come up with one possible approach and discover some variations, so they want to pull common code together. Abstract Base Class - fill in the common stuff here, let detailed implementers fill in the gaps. Help them by providing abstract methods saying "your code goes here". Note that these methods need not only be the ones in the Interface. Also note that this Abstract Base Class might even implement more that one Interface! (eg. It's CleverThingWorker but also a IntermediateWorkPersister.)

Then we have the role who actually do the fine detailed implementation. Fill in the gaps here. Dead easy to understand. In this case you don't even need to consider the Interface as such. Your job is to make that abstract class concrete.

Bottom line ... I use both Interfaces and Base classes. You put the Interface on the Base Class. We don't add value by adding it to the implementation class.

djna
A: 

The other thing that needs to be mentioned is that the use of interfaces makes it easier to implement automated tests.

Say, for example, that one of the methods of the interface is supposed to throw a exception - such as 'DatabaseConnectionLostException' - and you want to test client code to check that it behaves correctly in such a situation.

It is a simple matter to provide an implementation of the interface that throws the exception, allowing the test to be written.

If you used the abstract base class instead of the interface, this operation would be quite a bit trickier (OK, you can use Mocks, but the interface solution is much cleaner)

belugabob