Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid changing many parts of code when adding new enum value, thus providing easier extensibility?

I am trying to make my code easier to extend in terms that a little change will not affect much other code.

I have an enum MyEnum, which values might increase in future.

Then, there are classes that holds instance of it and has many behaviors affected by that enum's concrete value. In other words, there are many places where I switch over it's value.

public enum MyEnum
{
    FIRST, SECOND, THIRD, FOURTH;
}


public class A
{
    private MyEnum myEnum
    
    public A(MyEnum myEnum)
    {
        this.myEnum = myEnum;
    }
    
    // as you will see, there is a lot of switching over its value
    public void boo()
    {
        switch(myEnum)
        {
            case FIRST: // do smtng
            case SECOND: // do smthing else
            case THIRD: // do smthing else
            case FOURTH: // do nice thing
        }
    }

    public int goo()
    {
        switch(myEnum)
        {
            ...
        }
    }
   

    public AnotherObject foo()
    {
        switch(myEnum)
        {
            ...
        }
    }
}

public class B
{
    private MyEnum myEnum
    
    public B(MyEnum myEnum)
    {
        this.myEnum = myEnum;
    }
    
    public double doo()
    {
        switch(myEnum)
        {
            ...
        }
    }

    public void soo()
    {
        switch(myEnum)
        {
            ...
        }
    }
   
    public boolean xoo()
    {
        switch(myEnum)
        {
            ...
        }
    }
}

The thing here is that mostly I will need to add new case to all places where we switch over it's value => will need to do many changes to code when I add new enum value.

Did anyone else faced this problem? By now, I guess it is just downside of using enums this way.

like image 370
Wortig Avatar asked Dec 05 '21 21:12

Wortig


People also ask

Can we add constants to enum without breaking existing code?

4) Adding new constants on Enum in Java is easy and you can add new constants without breaking the existing code.

Can enum extend enum?

No, we cannot extend an enum in Java. Java enums can extend java. lang. Enum class implicitly, so enum types cannot extend another class.

How do I add value to an enum in Java?

You cannot create an object of an enum explicitly so, you need to add a parameterized constructor to initialize the value(s). The initialization should be done only once. Therefore, the constructor must be declared private or default. To returns the values of the constants using an instance method(getter).

Which class does all the enums extend?

Which class does all the Enums extend? Explanation: All enums implicitly extend java. lang. Enum.

Do the set of constants in an enum type stay fixed?

It is not necessary that the set of constants in an enum type stay fixed for all time. In Java (from 1.5), enums are represented using enum data type. Java enums are more powerful than C/C++ enums . In Java, we can also add variables, methods and constructors to it.

Why should I care about enum values?

Consistent use of enum values can make both libraries and APIs easier to use. If you accidentally mistype "Autumn" most editors won’t tell you that you got it wrong; but if you mistype Season.Autumn you’ll get an error, and your code won’t compile. How did customers know which enums to use?

How to extend an enum in Java?

As a class can only extend one parent in Java, so an enum cannot extend anything else. toString () method is overridden in java.lang.Enum class, which returns enum constant name. enum can implement many interfaces. These methods are present inside java.lang.Enum. values () method can be used to return all values present inside enum.

How do you find the value of an enum?

values () method can be used to return all values present inside enum. Order is important in enums.By using ordinal () method, each enum constant index can be found, just like array index. valueOf () method returns the enum constant of the specified string value, if exists. enum Color.


1 Answers

Don't bind your code to the enum bind your code to an interface. Then have your enum provide the standard implementations of the interface.

public interface RibbonColor {
   public String getColor();
}

public enum DefaultRibbonColors implements RibbonColor {
   FIRST() {
      public String getColor() {
        return "blue";
      }
   }, 
   SECOND() {
      public String getColor() {
        return "red";
      }
   },
   THIRD() {
      public String getColor() {
        return "white";
      }
   },
}

public class Awards {

   private List<RibbonColor> ribbons;

   public Awards(List<RibbonColor> ribbons) {
      this.ribbons = ribbons;
   }

   public RibbonColor awardFor(int placeIndex) {
      if (placeIndex < ribbons.length()) {
        return ribbons.get(placeIndex).getColor();
      }
      return null;
   }

}

Notice that now you can easily add in a new list of all the default Awards by

Awards awards = new Awards(Arrays.asList(DefaultRibbonColors.values()));

while you could also create custom awards sets.

List ribbons = new ArrayList<RibbonColor>();
ribbons.addAll(DefaultRibbonColors.values());
ribbons.addAll(ExtendedRibbonColors.values());
ribbons.addAll(new BlackAndPinkPolkaDotRibbonColor());

Awards awards = new Awards(ribbons);

The key is to never make the code actually depend on the enum because you can't modify an enum without recompiling, and that triggers the need to search for switch statements that lack default: blocks or more explicit settings for the added value.

Objects are "code and data written together" while procedural code is "code and data managed separately" The switch statement puts the logic "code" outside of the type "data" and is a programming mistake in 100% insanely object oriented design. That said, it is often useful, and people still structure programs in Java and other languages in ways that effectively separate code from data (object that hold all the data, and "object routines" that manipulate another object's data. This kind of separation of an object's data from its routines is an antipattern called anemic objects.

Enums are Objects so don't be afraid to put methods in them! Give them interfaces where they should be replicable, and avoid switch statements because it's probably a good sign that the logic should be in the thing you are switching on (provided it is an Object).

like image 107
Edwin Buck Avatar answered Oct 25 '22 01:10

Edwin Buck