I have a problem to understand how to solve parallel inheritance.
Definition of Parallel Inheritance
Fowler definies parallel inheritance as follows [1, page 68]:
Parallel inheritance hierarchies is really a special case of shotgun
surgery. In this case, every time you make a subclass of one class,
you also have to make a subclass of another. You can recognize this
smell because the prefixes of the class names in one hierarchy are the
same as the prefixes in another hierarchy.
Problem
In the Book
Refactoring in Large Software Projects: Performing Complex Restructurings, page 46 the author displays the following parallel inheritance:
Then he solves the parallel inheritance with composition and says:
In many cases, parallel inheritance hierarchies can be resolved in
such a manner that only one inheritance hierarchy is left, while the
classes of other inheritance hierarchies are integrated through use.
The solution looks like this:
So the author and Fowler concludes that a parallel inheritance can be solved with
The general strategy for eliminating the duplication is to make sure
that instances of one hierarchy refer to instances of the other.
The problem which I see is the classes are still there and if I add a new class a new '*ListView' class must be added.
But for this problem Fowler says:
If you use Move Method and Move Field, the hierarchy on the referring
class disappears.
For the current case this means I move the method to display the entities
in the entity classes?
So this will hurts the MVC principal or not?!
QUESTION
So how to solve parallel inheritance at all
and especially in UI cases?
SOURCE:
1 Martin Fowler 'Refactoring: Improving the Design of Existing Code'
[Book: Refactoring in Large Software Projects: Performing Complex Restructurings, page 46]
There are several ways of solving this, depending on the case. Here I present two possible solutions:
Note: I will use some scala-like pseudo code for the examples just because is short and readable
List Adapter & Generics
Based on implementations from:
- Android ListView
- Javax JList
- Arena MVVM Framework
Initially, ListView
could have a default adapter which requires its adaptees to implement some interface, let's call it Nameable
. And uses it to render each item.
class BasicListViewAdapter extends ListAdapter[Nameable]
//on scala it would be a trait, but I'll call it interface just for the sake of the example
interface Nameable {
def getName():String
}
Of course, not all the classes will be rendered exactly the same way. This is solved by the use of an Adapter.
class Partner implements Nameable
class Customer extends Partner {
def getName = { this.getClientCode + " " + this.getFullName }
/* some implementation*/
}
class Supplier extends Partner {
def getName = { this.getCompanyName }
/* some implementation*/
}
Where a ListView
of suppliers will generate a list of company names and a ListView
of customers will display a list of client codes with their respective names (whatever, just an example).
Now, if we want to make more complex lists, we could feed the ListView with a custom adapter.
class PhoneNumberAdapter extends ListAdapter[Supplier] { /*...*/}
val supliersWithPhoneNumbers = new ListView
supliersWithPhoneNumbers.useAdapter(new SupplierWithPhoneNumberAdapter)
Using this technique, you no longer need one ListView class per model class, and only define custom adapters for special cases. The better your default adapter and your hierarchy, the less code you will need.
For another example, you can take a look at https://codereview.stackexchange.com/questions/55728/a-generic-mvc-arrayadapter-class
Mixins / Traits
Instead of using composition, if your language of choice allows it (and if you philosophically agree), you might use mixins or traits. I'll not dive in the differences between the two, and just use mixins (for more information: Mixins vs. Traits).
By using mixins you are able to decompose behaviour on a more refined way, unlocking a variety of new patterns and solutions (even more if you add some structural typing and other features).
For instance, back to the ListView case, each rendering strategy could be incorporated by the ListView, looking like:
trait NameAndPhoneNumber {
//we require this trait to be incorporated on some class of type ListView
this:ListView[{def getName:String }] =>
override def render = ...
}
//where ListView is covariant
new ListView[Supplier] with NameAndPhoneNumber
Where NameAndPhoneNumber
could be applied to several classes, not only Customer or Supplier.
In fact, it might be refactored to:
new ListView[Supplier] with NameRendering with PhoneRendering
And make use of the Stackable Traits pattern (more info (here)[http://dl.acm.org/citation.cfm?id=2530439] and (here)[http://www.artima.com/scalazine/articles/stackable_trait_pattern.html])
References:
- Traits paper
- Mixins paper
- Sibiling pattern
- A case: Backbonejs
- (Stackable Traits Pattern)[http://www.artima.com/scalazine/articles/stackable_trait_pattern.html]