Avoiding code duplication when overriding abstract methods in enum

I am implementing a state machine in enum in Java. I have a toy example below, where I transition between X,Y and Z states based on group membership.

The issue is, the transition rule for Y and Z are identical (i.e., the Overriden methods are identical).

Is there any way to avoid code duplication here? In my real life example, it is a bit more severe so the code duplication potential is worse.

enum Group {
    A,B,C
}

enum Element {
    X(Group.A) {
        @Override
        public Element getNextElement(Element nextElement) {
            if(nextElement.getGroup() == Group.B) {
                return nextElement;
            } else {
                return this;
            }
        }
    },
    Y(Group.B) {
        @Override
        public Element getNextElement(Element nextElement) {
            if(nextElement.getGroup() == Group.A) {
                return nextElement;
            } else {
                return this;
            }
        }
    },
    Z(Group.C) {
        @Override
        public Element getNextElement(Element nextElement) {
            if(nextElement.getGroup() == Group.A) {
                return nextElement;
            } else {
                return this;
            }
        }
    };

    Group group;

    Element(Group group) {
        this.group=group; 
    };

    public Group getGroup() {
        return this.group;
    }

    public abstract Element getNextElement(Element nextElement);

}
Jon Skeet
people
quotationmark

Given that your logic is identical except for the value in the transition rule, you can just parameterize by that:

enum Element {
    X(Group.A, Group.B),
    Y(Group.B, Group.A),
    Z(Group.C, Group.A);

    private final Group group;
    private final Group nextGroup

    private Element(Group group, Group nextGroup) {
        this.group = group; 
        this.nextGroup = nextGroup;
    }

    public Group getGroup() {
        return this.group;
    }

    public Element getNextElement(Element nextElement) {
        return nextElement.getGroup() == nextGroup ? nextElement : this;
    }
}

You can still override getNextElement in some values. For example:

enum Element {
    X(Group.A, Group.B) {
        @Override public Element getNextElement(Element nextElement) {
            return someRandomCondition ? nextElement : this;
        }
    }
    Y(Group.B, Group.A),
    Z(Group.C, Group.A);

    // Other code as above
}

people

See more on this question at Stackoverflow