0

I have an Enum which has three constants as of now. All three are having 10+ overridden methods. Is it possible to have a better design so that I can put all of them to a common class.

Updated with sample code:

public enum MyEnum {

    FIRST {
        @Override
        public String doIt() {
            return "1: " + someField; //error
        }
        @Override
        public String getCategory() {
            return "MyCategory1"; //error
        }
    },
    SECOND {
        @Override
        public String doIt() {
            return "2: " + someField; //error
        }
       @Override
        public String getCategory() {
            return "MyCategory2"; //error
        }
    },
    THIRD {
        @Override
        public String doIt() {
            return "3: " + someField; //error
        }
       @Override
        public String getCategory() {
            return "MyCategory3"; //error
        }
    };

    private String someField;

    public abstract String doIt();
    public abstract String getCategory();

}
RoyalTiger
  • 511
  • 2
  • 8
  • 27
  • an enum is a single class. What exactly are you talking about? – Stultuske Apr 16 '20 at 05:52
  • If you're overriding too many methods on your enum values, then perhaps you need to find a better way to reuse the code. One option is to make those values pass an instance that implements those methods, but this solves little than by cleaning up your enum class. I think you'll need to post your code to make it clearer. – ernest_k Apr 16 '20 at 06:01
  • @ernest_k I've updated with a sample code. You can see there are a number of overridden methods and this can increase in time. Is it possible to use some other structure instead of this – RoyalTiger Apr 16 '20 at 06:14
  • 1
    why override those methods? just have one method, and have an int value id which you set when creating the enum values? – Stultuske Apr 16 '20 at 06:15
  • 1
    There's no difference in behavior here, just the data differs. So I'd do exactly what @Stultuske suggests (except that you'd have two, non-abstract, methods; and the field needs not be of type int) – ernest_k Apr 16 '20 at 06:18
  • This is just an example of my actual class. Each of these methods is actually doing more than just returning a value. Like performing an operations each time being called. – RoyalTiger Apr 16 '20 at 06:21
  • 2
    @RoyalTiger then you should at least show a minimal example that shows so. But, if each enum value is supposed to do something different, why would you use enums? – Stultuske Apr 16 '20 at 06:22
  • 2
    You can also use a single method with a `switch(this)` statement instead of overriding the method. – Holger Apr 16 '20 at 06:23
  • 1
    Change `someField` to be **`protected`**. --- However, where does the value of `someField` come from? Remember that all the enum constants are singletons, so the value shouldn't come from some arbitrary code, so how is the value initialized? Depending on the answer to that, there might be better ways to do this. – Andreas Apr 16 '20 at 06:24
  • 1
    @Andreas package-private should be enough. Or just access the field via `super.someField`. – Holger Apr 16 '20 at 06:26
  • @Stultuske I agree. your suggestion is valid. Let me see by trying to modify it now. – RoyalTiger Apr 16 '20 at 06:26
  • @Holger One of the many goals of `enum` is to eliminate the need for `switch` statements, so writing a `switch` statement inside an `enum` is counter-productive. – Andreas Apr 16 '20 at 06:27
  • Yes, we should not use switch statement here. I mean that's what Enum is doing. – RoyalTiger Apr 16 '20 at 06:28
  • 1
    @Andreas there are pros and cons and I also would avoid that, still, I think a `switch` statement encapsulated within an `enum` is not the same as an arbitrary `switch` statement, but rather an implementation detail. Of course, it works better with the new language proposals, which allow to omit the `default` label and get an error if one case is missing… – Holger Apr 16 '20 at 06:30
  • 1
    @Holger They specifically added the ability to add constructor arguments and to write method overrides for each constant to eliminate the need for `switch` statements in the enum, so why not use the language features designed for the purpose? – Andreas Apr 16 '20 at 06:32
  • 1
    @Andreas they also specifically added the ability to switch over an enum type, so why not use *that* language feature designed for that purpose? There is no black and white. I neither recommend `switch` as the first choice nor do I recommend heavily using overriding. See [this example](https://stackoverflow.com/a/28277973/2711488), overriding for handling the special case while having a common implementation for the standard case, that’s what I consider useful. You can also [use delegation](https://stackoverflow.com/a/42485934/2711488). – Holger Apr 16 '20 at 06:45
  • @Holger Because someone might need ability to do something different for each enum constant, without having the abililty to modify the `enum` (standard Java Runtime Library enum, or enum from third-party library). – Andreas Apr 16 '20 at 06:47
  • 1
    @Andreas that would also be solvable with an `EnumMap`. The presence of one feature is not a proof that another feature must not be used. To me, overriding a method in every enum constant is just a verbose version of a `switch` statement, it does not make the code cleaner in any regard. – Holger Apr 16 '20 at 06:51
  • @Holger Sure it does. It force a developer adding a new enum to implement the abstract method. But it seems we'll have to agree to disagree on this topic. – Andreas Apr 16 '20 at 06:54
  • 1
    @Andreas so does a `switch` statement with the most recent language version when you omit the `default` label. For the previous versions, any decent IDE will tell you. Eclipse even allows to treat it as an error. But as said, it’s not my first choice, I already named alternatives to both, overriding a method in every constant and using a switch. But this question is specifically about avoiding the disadvantages of overriding a method in every constant, so even when not recommending it, the option should be named. – Holger Apr 16 '20 at 07:05

2 Answers2

2

Why not try it like this:

public enum MyEnum{
    FIRST(1),
    SECOND(2),
    THIRD(3);

    private final int value;

    private MyEnum(int value) {
        this.value = value;
      }

    public String doIt() {
        return value + ": " + someField;
    }

    public String getCategory() {
        return "MyCategory" + value;
    }
}

There is no need to repeat any methods, let alone to override them.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
Stultuske
  • 9,296
  • 1
  • 25
  • 37
  • 1
    those were just a copy paste from the question :) – Stultuske Apr 16 '20 at 06:34
  • Of course, you don't have a `someField` value, and we don't even know where such a value would come from, so that's still a huge outstanding issue, before a final answer can be given. – Andreas Apr 16 '20 at 06:36
0

If you want specifically a class:

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class Category {

    public static final Category FIRST = new Category(1, "MyCategory1", "someField");
    public static final Category SECOND = new Category(2, "MyCategory2", "someField");
    public static final Category THIRD = new Category(3, "MyCategory3", "someField");

    private int categoryId;
    private String category;
    private String someField;

    public String doIt() {
        return this.categoryId +": " + this.someField;
    }


}

And then just use constants:

public class TestCategory {

    public static void main(String[] args) {
        System.out.println(FIRST.doIt());
        System.out.println(FIRST.getCategory());
    }

}
IKo
  • 4,998
  • 8
  • 34
  • 54