Pioneer Plot: Cleansed Domain Layer
The last Pioneer Plot posed a dilemma: a Factory class for Legacy Objects takes in an Entity, which is polymorphic, and spits out an equivalent Legacy Object. You want all references in your domain layer to be self-contained so that it focuses on domain logic. What do you do?
My answer
Since polymorphism is involved, the first instinct is to double dispatch:
interface Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory);
}
class OneEntity implements Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory)
{
return factory.newLegacyObjectFrom(this);
}
}
class AnotherEntity implements Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory)
{
return factory.newLegacyObjectFrom(this);
}
}
class LegacyFactory
{
LegacyObject newLegacyObjectFrom(Entity e)
{
return e.asLegacyObjectWith(this);
}
LegacyObject newLegacyObjectFrom(OneEntity e)
{
... logic here ...
}
LegacyObject newLegacyObjectFrom(AnotherEntity e)
{
... logic here ...
}
}
Pretty standard. But there are issues. First, the Entity interface contains a non-domain reference to LegacyObject. Second, LegacyFactory is in an anti-corruption layer, which uses the domain layer, and now the domain layer has a reference into the anti-corruption layer, causing a circular dependency. Crap.
Option 1
Option 1 is…forget the anti-corruption layer and put it all into the domain layer. I know, I laughed too.
Option 2
Option 2 is to bite it and use instanceof.
class LegacyFactory
{
LegacyObject newLegacyObjectFrom(Entity e)
{
if(e instanceof OneEntity)
{
OneEntity entity = (OneEntity)e;
... logic here ...
}
if(e instanceof AnotherEntity)
{
AnotherEntity entity = (AnotherEntity)e;
... logic here ...
}
throw new RuntimeException();
}
}
The smells here should be obvious, but the advantage is that the Entity interface no longer refers to the anti-corruption layer and there is no circular dependency.
Option 3
Option 3 is to change your architecture to include an intermediate package that both the domain layer and the anti-corruption layer use. This way, all references flow downward. You know, invert the dependency.
// domain layer
interface Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory);
}
// domain layer
class OneEntity implements Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory)
{
return factory.newLegacyObjectFrom(this);
}
}
// domain layer
class AnotherEntity implements Entity
{
LegacyObject asLegacyObjectWith(LegacyFactory factory)
{
return factory.newLegacyObjectFrom(this);
}
}
// anti-corruption layer
class LegacyFactoryImpl implements LegacyFactory
{
LegacyObject newLegacyObjectFrom(Entity e)
{
return e.asLegacyObjectWith(this);
}
LegacyObject newLegacyObjectFrom(OneEntity e)
{
... logic here ...
}
LegacyObject newLegacyObjectFrom(AnotherEntity e)
{
... logic here ...
}
}
// intermediate layer
interface LegacyFactory
{
LegacyObject newLegacyObjectFrom(Entity e);
LegacyObject newLegacyObjectFrom(OneEntity e);
LegacyObject newLegacyObjectFrom(AnotherEntity e);
}
However, if you try to actually do this, you’ll find it to be impossible with the double dispatch constraint. There is still a circular dependency between the domain layer and intermediate layer. If you decide to merge these two, then you have the domain layer with a reference to LegacyObject. The best you can do is fudge it:

That intermediate layer becomes a special part of the domain layer that is allowed to hold “impure” (non-domain) references. I find this to be quite artificial.
So?
I actually don’t have a good answer here. Each option has philosophical questions to answer in lieu of its acceptance. Choosing Option 2 means you accept that some tight coupling is acceptable in a factory, namely coupling to a class hierarchy. Choosing Option 3 means you place a high premium on referential integrity and are OK with sub-packages referencing their parents. Choosing Option 1 means you think Option 3 is not worth the effort, but that you also have the discipline to not let too many “impure” references to leak into the domain layer.
COME my tan-faced children,
Follow well in order, get your weapons ready,
Have you your pistols? have you your sharp-edged axes?
Pioneers! O pioneers!
For we cannot tarry here,
We must march my darlings, we must bear the brunt of danger,
We the youthful sinewy races, all the rest on us depend,
Pioneers! O pioneers!
![]() |
Announcer: You’re reading the EIP web-ring. |
