I am trying to extend some existing code that implements a tree using composite pattern. As expected from this pattern, there is an interface
(Node
) and an abstract class (AbstractNode
) representing a generic node. The latter is extended by multiple concrete types of nodes (ConcreteNodeA
, ConcreteNodeB
, ConcreteNodeC
).
I encountered this other pattern in the code that I am working with, in which the concrete classes are implemented as static inner classes, extending the outer abstract class. And at the same time they implement static inner interfaces (NodeA
, NodeB
, NodeC
) from the outer(?) interface Node
.
public interface Node {
public static interface NodeA {}
public static interface NodeB {}
public static interface NodeC {}
}
public abstract class AbstractNode implements Node {
public void foo() {
...
}
public void bar() {
...
}
...
public static class ConcreteNodeA extends AbstractNode implements Node.NodeA {
...
}
public static class ConcreteNodeB extends AbstractNode implements Node.NodeB {
...
}
public static class ConcreteNodeC extends AbstractNode implements Node.NodeC {
...
}
}
What is the use of this pattern? Through many years of experience with Java, I have never seen something like this before. My intuition says it is a massive code smell, as the concrete classes are constantly instantiated and used many times throughout the code. Anyway, I am not worried about efficiency, it is just that this is so difficult to mantain and extend!. It would make more sense to have them in separate classes, right?
I have searched for more formal references to prove it is bad idea to do it this way, but have not found anything yet.
There is no compiltation error, and the code works perfectly.
This pattern is actually quite common when describing related families of types, such as the nodes of a tree.
One reason is simply that it is a convenient grouping; these classes tend to be individually small, and having them all in one place can make it easier to read and maintain, as well as sending the signal that they are a tightly coupled family and intended to be used together.
A more compelling reason is that it can provide a form of sealed classes. By having a private constructor in the abstract class, only the inner classes can access it, meaning that the inner classes are the only allowed subclasses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With