views:

303

answers:

4

I have a class A which implements many functions. Class A is very stable. Now I have a new feature requirement, some of whose functionality matches that implemented by A. I cannot directly inherit my new class from class A, as that would bring lot of redundancy into my new class.

So, should i duplicate the common code in both the classes?

Or, should i create a new base class and move the common code to base class, and derive class A and the new class from it? But this will lead to changes in my existing class.

So, which would be a better approach?

+15  A: 

Unless there is a very good reason not to modify class A, refactor and make a common base (or even better, a common class that both can use, but not necessarily derive from).

You can always use private inheritance to gain access to the shared functionality without modifying class As external interface - this change would require a rebuild, but nothing more. Leave all the functions on class A, and just have them forward to the shared implementation class.

One reason you might not want to refactor, but rather copy the code is if it's likely that the new class' functionality will change, but without the same change being needed in the old class. One of the reasons for not duplicating code is so that a fix or a change needs only to be made in one place. If changes are going to happen that will break the original class, then maybe you want to copy the code instead. Although in most cases, this will only happen if the two classes aren't as similar as you thought, and you'd be fighting to try and abstract a common set of functionality.

Eclipse
You are right. My new class implementation most likely to change in future and may not share same implementation with class A.
chappar
Of course you're still likely better off moving the common stuff into a class somewhere and using that in the meantime.
Eclipse
+1 for saying the common code could go in a class used by A and B instead of being in a base class of A an B.
Scott Langham
+1 for Composition.
Jason Punyon
+7  A: 

(1) Do not duplicate the common code in both classes unless you or your employer are prepared to maintain both copies indefinitely.

(2) Refactoring by definition changes classes you already have. The refactor you propose is called "Extract SuperClass" followed by "Pull Up Method" for each method that is common to the derived classes. This is a fine approach.

Edit: I remembered the real gem behind Refactoring: Within reason it is perfectly fluid and reversible. There is never a "Right" there is only a "Right for now". If you decide later that using inheritance for these classes isn't a good object model then you can refactor again to use composition (as superbly suggested by Josh).

Jason Punyon
+1  A: 

Classes should share a common base class if you intend the classes to be substitutable (the "IS-A" relationship).

You might consider composition. Your new class B could be a wrapper class around a private member variable of type class A. Class B could augment class A with new methods or logic without changing class A. This is convenient if you can't change class A (e.g. it is closed source software, owned by another team, or you are afraid to break compatibility with existing code using class A).

For a nice diagram, see "Replace Inheritance with Delegation" refactoring pattern.

cpeterso
A: 

Assuming that you don't have them, a very good start would be to create unit tests (let's call them ATest) for A's functionality.

Later, you could refactor: identify the common part, move it to another class C, call it from A (hopefully calling it will be enough, without the need to derive from C - especially if it is not true that, conceptually, "an A is a C"). It should be really easy to move also the part of your unit tests which actually refers to the new C, to a CTest class.

Finally, add functionality by designing the new class B so that it also takes advantage from C's features (typically, by calling them, in a similar way that A does). In parallel, you could design BTest to express and test B's expected behaviour.

Daniel Daranas