I have a composite like pattern in where there is different functionality for the roots of the trees, branches and leafs. The problem is that there is a shared state between both Root with Branch and Branch with Leaf. I'm searching for the cleanest solution which prevents code duplication.
The functionality among root, branch and leaf all relate to the same set of methods (though leaf has different signatures).
The problem the implementation is the same for Branch and Leaf and implementing it would cause duplicate code. It's impossible to make Embeddable an abstract class because Branch already extends Composite.
I'm searching for a pattern or general solution so that Branch can share state with Embeddable and Composite at the same time. Basically a multiple-inheritance workaround.
This design is in practice used to structure a 3D block environment. Root being infinite in space, branches are a subsection with an offset in the space of its parent and leaves represent 1 block relative to its parent offset. Some functionality for root and branch thus requires coordinates as parameters, whereas leaf won't require those, since it's already at 1 coordinate.
public abstract class Container{
private List<Embeddable> children;
private WeakHashMap<Integer, Leaf> leafs;
public abstract boolean setBlock(short x, short y, short z, byte id, byte data, SetBlockStrategy setBlockStrategy);
public abstract void tick();
public abstract void activate(short x, short y, short z);
protected final Leaf getLeaf(short x, short y, short z) { ... }
protected void addChild(short x, short y, short z, Embeddable child) { ... }
}
public interface Embeddable {
void setParent(Container parent, short x, short y, short z);
void clearParent();
Container getParent();
}
public class Root extends Composite {
private RootSpecificObject rootSpecificParameter;
public boolean setBlock(short x, short y, short z, byte id, byte data, SetBlockStrategy setBlockStrategy) {
controller.doStuff();
}
public void tick() {
controller.doStuff();
}
public void activate(short x, short y, short z) {
controller.doStuff();
}
}
public class Branch extends Composite implements Embeddable {
private BranchSpecificObject branchSpecificParameter;
// Duplicate code
private short xOffset, yOffset, zOffset;
private Container parent;
public boolean setBlock(short x, short y, short z, byte id, byte data, SetBlockStrategy sbs) {
parent.setBlock(x + xOffset, y + yOffset, z + zOffset, id, data, sbs);
}
public void tick() {
controller.doStuff(xOffset, yOffset, zOffset, ...);
}
public void activate(short x, short y, short z) {
parent.activate(x + xOffset, y + yOffset, z + zOffset);
}
// Duplicate Embeddable implementation
}
public class Leaf implements Embeddable {
private byte id, data;
// Duplicate code
private short xOffset, yOffset, zOffset;
private Container parent;
public boolean setBlock(byte id, byte data, SetBlockStrategy sbs) {
return parent.setBlock(xOffset, yOffset, zOffset, id, data, sbs);
}
public void activate(short x, short y, short z) {
parent.activate(xOffset, yOffset, zOffset, id, data, sbs);
}
// Duplicate Embeddable implementation
}
It's not clear what exact code is duplicated, but the common way for such problem is to delegate state and behavior to another class.
Remember there's always a trade-off between readability and easiness to maintain such code. Think twice now that you really need to avoid code duplication.
Short example for your code
public class Branch extends Composite implements Embeddable {
EmbeddableDelegate delegate;
}
public class Leaf implements Embeddable {
EmbeddableDelegate delegate;
}
public class EmbeddableDelegate [implements Embeddable] {
private short xOffset, yOffset, zOffset;
private Container parent;