While I write OOP code I apply some practices of Elegant Objects.
One of them is that classes should be final. This means that they cannot be extended through inheritance but only through composition.
The advantage is simplicity. I mean that, in this way, each object is seen as a cohesive block. What interest to its clients is its exposed behaviour. Nothing more. Instead, through extension, a client can break it.
For instance, an object can interrelate two of its methods. So, if we can replace through extension one of them we can break the other. For this reason, to be sure, we should check its implementation. In this way we increase coupling between the extended and the extension.
In other words, final classes enforces the idea that we should care only of exposed behaviour. And not of implementation. Nonetheless, it requires a change of how we reason about them. The Alias pattern simplifies an aspect of this change.
Intent
The Alias pattern allows to extend the way a class can build its objects without subclassing or modifying it.
Motivation
Suppose a final class that creates its objects using some mandatory parameters. How can we add another way to create its objects? For instance, how we can add a constructor that use a default value for one or more of its missing parameters?
One approach could be to add another constructor to the class. But this could get out of hand. Furthermore, it could be not possible. For instance, the aforesaid final class could be in an external library.
Another drawback of this approach is that we can pollute the final class. For instance, we can have a final class that builds its objects given a JSON. But after some time we need to add also XML. As you can imagine adding the code to map XML to JSON will pollute inevitably that class.
However, the Alias pattern isn’t limited to final classes. For instance, we cannot have two constructors with same parameters but different semantic.
To resolve this issue we can add static factory methods to the class code. But the same aforesaid drawbacks affects this approach. That is: this gets out of hand; this couldn’t be always possibile; this will pollute the class.
A better approach to both problems is to create another class with the desired constructor behaviour. This class encapsulates its own construction logic. And it will delegate everything to the other class, including the actual creation. This is the Alias pattern.
Applicability
Use the Alias pattern when:
- You need to add or modify a constructor of a final class;
- You want to add or modify a constructor of a class without modifying or subclassing it;
- You need two or more constructor of a class with the same parameters without modifying or subclassing it.
Structure
The structure is simple. We need at least two class that implements the same interface: an Alias
and an Aliased
.
Partecipants
AnInterface
- declares an interface.
Aliased
- implements
AnInterface
; - exposes one or more constructors.
- implements
Alias
- implements
AnInterface
; - exposes one or more constructors;
- maintains a reference to an
Aliased
object; - delegates everything to the referenced
Aliased
object.
- implements
Collaboration
Alias
builds - according to its own rules - anAliased
object and maintains a reference of it. Then it delegates everything to the aliased.
Consequences
The Alias Pattern has the following consequences:
- It allows adding or modifying constructors easy;
- It promotes composition over inheritance;
- It increases the number of classes;
- It reduces code duplication when used to replace a recurrent creation;
- Alias classes duplicates delegating code. If this is a problem it could be approach with a base abstract Alias class.
Implementation
To implement the Alias pattern you need:
- to define an interface;
- to implement the previously defined interface with a class. This will be the aliased one;
- to implement the previously defined interface with an alias class, and you need:
- to define a constructor that builds an aliased object according some needs;
- a private instance variable that reference to the previously built aliased object;
- to delegates everything to the aliased object.
Sample Code
The below Java-ish code expresses the Alias pattern. In this code the alias injects a default value for an otherwise mandatory parameter:
interface AnInterface {
void aMethod();
Something anotherMethod();
}
final class Aliased implements AnInterface {
private final A a;
private final B b;
Aliased(final A a, final B b) {
this.a = a;
this.b = b;
}
void aMethod() {
// implementation
}
Something anotherMethod() {
// implementation
}
}
final class Alias implements AnInterface {
private final Aliased aliased;
Alias(final A a) {
this(
new Aliased(
a,
new InstanceOfB(...)
)
);
}
private Alias(final Aliased aliased) {
this.aliased = aliased;
}
void aMethod() {
this.aliased.aMethod();
}
Something anotherMethod() {
return this.aliased.anotherMethod();
}
}
Related Patterns
At a certain degree, the Alias pattern could be also seen as a way to decorate the objects construction. This vision is especially true if we see a class as an object which responsibility is to create objects.