Vivek Ranjan
Vivek Ranjan

Reputation: 3

Best way to refactor this code, if enums are not extensible

Consider the following class that represent a entity and has method which return data of type EnumA

EntityA class:

public class EntityA
{   
    public Set<EnumA> getProcessedFlags() { ... }
}

EnumA:

public enum EnumA {
  READ_ONLY,
  READ_WRITE,
  PERMISSION_DENIED,
  COMMENT_ENABLED
}

Now I got the requirement to add one more EntityB, which is similar to EntityA, but logically different. (Same method signatures but different implementation:

There is one more thing, the return value which was EnumA in EntityA, is **EnumB for EntityB.

EnumA and EnumB are two different set, which represent a collection of logically same flags, but have some exclusive values in each of them:

EnumB

public enum EnumB {
  READ_ONLY,
  READ_WRITE,
  LIKE_ENABLED
}

So To refactor this, I made a abstract base class - EntityBase, and made both EntityA and EntityB, child of this base class.

Problem is enums are not extensible, Is there a good way to refactor this?

I thought of creating class structure something like this below:

public enum EnumBase {}

public enum EnumA extends EnumBase {}

public enum EnumB extends EnumBase {}

public abstract class EntityBase
{
  public Set<? extends EnumBase> getProcessedFlags();
}

public class EntityA extends EntityBase
{   
    public Set<EnumA> getProcessedFlags() { ... }
}

public class EntityB extends EntityBase
{   
    public Set<EnumB> getProcessedFlags() { ... }
}

Since Enums in java are not extensible, Can we have some better design to maintain this EntityBase class?

Upvotes: 0

Views: 242

Answers (2)

magicmn
magicmn

Reputation: 1914

A different solution would be to use one enum for all PermissionsFlags and then add an attribute that allows you to check if the PermissionFlag can be used with this class.

public enum PermissionFlag {
    READ_ONLY,
    READ_WRITE,
    PERMISSION_DENIED(EntityA.class),
    COMMENT_ENABLED(EntityA.class),
    LIKE_ENABLED(EntityB.class);

    private final Class<?> useForClass;

    PermissionFlag() {
        this(null);
    }

    PermissionFlag(Class<?> useForClass) {
        this.useForClass = useForClass;
    }

    /**
     * Check if given class can be used for this PermissionFlag.
     */
    public boolean useForClass(Class<?> clazz) {
        return useForClass == null || useForClass.equals(clazz);
    }

    /**
     * Returns a Stream consisting of all the PermissionFlags that can be used with the given class.
     */
    public static Stream<PermissionFlag> getPermissionsFlags(Class<?> clazz){
        return Stream.of(values()).filter(flag -> flag.useForClass(clazz));
    }
}

And then you can use getPermissionFlags(EntityA.class).collect(Collectors.toList()) to get a List of all the Permissions flag for EntityA.

Upvotes: 1

shmosel
shmosel

Reputation: 50716

Hard to offer specific advice without more context, but it's worth noting that enums can share interfaces, so you can try something like this:

interface Base {
    String name();
}

interface A extends Base {}
interface B extends Base {}

public enum EnumBase implements A, B {
    READ_ONLY,
    READ_WRITE
}

public enum EnumA implements A {
    PERMISSION_DENIED,
    COMMENT_ENABLED
}

public enum EnumB implements B {
    LIKE_ENABLED
}

public abstract class EntityBase<F extends Base> {
    public abstract Set<F> getProcessedFlags();
}

public class EntityA extends EntityBase<A> {
    @Override
    public Set<A> getProcessedFlags() { ... }
}

public class EntityB extends EntityBase<B> {
    @Override
    public Set<B> getProcessedFlags() { ... }
}

Upvotes: 2

Related Questions