添加新枚举值时如何避免更改代码的许多部分,从而提供更容易的可扩展性?

Wor*_*tig 6 java enums extensibility design-patterns software-quality

我试图让我的代码更容易扩展,因为一点点的改变不会影响其他代码。

我有一个enum MyEnum,其值将来可能会增加。

然后,有一些类保存它的实例,并且许多行为受到该enum的具体值的影响。换句话说,有很多地方我切换了它的值。

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)
        {
            ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是,大多数情况下,我需要将新的情况添加到我们切换其值的所有位置=>当我添加新的枚举值时,需要对代码进行许多更改。

还有其他人遇到过这个问题吗?到目前为止,我想这只是以这种方式使用enum的缺点。

Edw*_*uck 9

不要将您的代码绑定enum到接口。然后让您的枚举提供接口的标准实现。

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;
   }

}
Run Code Online (Sandbox Code Playgroud)

请注意,现在您可以轻松添加所有默认值的新Awards列表

Awards awards = new Awards(Arrays.asList(DefaultRibbonColors.values()));
Run Code Online (Sandbox Code Playgroud)

同时您还可以创建自定义奖励集。

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

Awards awards = new Awards(ribbons);
Run Code Online (Sandbox Code Playgroud)

关键是永远不要让代码实际上依赖于,enum因为如果不enum重新编译就无法修改,并且这会触发需要搜索switch缺少的语句default:块或更明确的附加值设置的语句。

对象是“一起编写的代码和数据”,而过程代码是“代码和数据分开管理”。该switch语句将逻辑“代码”置于类型“数据”之外,并且是 100% 疯狂的面向对象设计中的编程错误。也就是说,它通常是有用的,人们仍然以有效地将代码与数据(保存所有数据的对象,以及操作另一个对象的数据的“对象例程”)分离的方式用 Java 和其他语言构建程序。来自其例程的对象数据是一种反模式,称为anemic objects

Enums所以Objects不要害怕在其中添加方法!为它们提供可复制的接口,并避免使用 switch 语句,因为这可能是一个好兆头,表明逻辑应该位于您要打开的事物中(前提是它是一个对象)。