Object-oriented – Duplication in parallel inheritance hierarchies

designdesign-patternsdomain-driven-designobject-orientedobject-oriented-design

Using an OO language with static typing (like Java), what are good ways to represent the following model invariant without large amounts of duplication.

I have two (actually multiple) flavours of the same structure. Each flavour requires its own (unique to that flavour data) on each of the objects within that structure as well as some shared data. But within each instance of the aggregation only objects of one (the same) flavour are allowed.

FooContainer can contain FooSources and FooDestinations and associations between the "Foo" objects
BarContainer can contain BarSources and BarDestinations and associations between the "Bar" objects

interface Container()
{
   List<? extends Source> sources();
   List<? extends Destination> destinations();
   List<? extends Associations> associations();
}

interface FooContainer() extends Container
{
   List<? extends FooSource> sources();
   List<? extends FooDestination> destinations();
   List<? extends FooAssociations> associations();
}

interface BarContainer() extends Container
{
   List<? extends BarSource> sources();
   List<? extends BarDestination> destinations();
   List<? extends BarAssociations> associations();
}

interface Source
{
   String getSourceDetail1();
}

interface FooSource extends Source
{
   String getSourceDetail2();
}

interface BarSource extends Source
{
   String getSourceDetail3();
}

interface Destination
{
   String getDestinationDetail1();
}

interface FooDestination extends Destination
{
   String getDestinationDetail2();
}

interface BarDestination extends Destination
{
   String getDestinationDetail3();
}

interface Association
{
   Source getSource();
   Destination getDestination();
}

interface FooAssociation extends Association
{
   FooSource getSource();
   FooDestination getDestination();
   String getFooAssociationDetail();
}

interface BarAssociation extends Association
{
   BarSource getSource();
   BarDestination getDestination();
   String getBarAssociationDetail();
}

Best Answer

Generic programming is your friend:

interface Association<S extends Source, D extends Destination> {
   S getSource();
   D getDestination();
}
interface FooAssociation extends Association<FooSource, FooDestination> {
   String getFooAssociationDetail();
}
interface BarAssociation extends Association<BarSource, BarAssociationDetail> {
   String getBarAssociationDetail();
}

interface Container<S extends Source, D extends Destination, A extends Association<S, D>> {
   List<? extends S> sources();
   List<? extends D> destinations();
   List<? extends A> associations();
}
interface FooContainer extends Container<FooSource, FooDestination, FooAssociations> {}
interface BarContainer extends Container<BarSource, BarDestination, BarAssociations> {}    

I am not a Java programmer, so please excuse any mistakes. It should give you an idea however.
Please note that the type parameter constraints are not necessary to build up your type hierarchy, but they better communicate the purpose of the generic base interfaces.

Related Topic