Java中使用枚举的一种方法类

3

我有一个枚举类型,长这样

public enum MyEnum
{
  myValue
  {
    @Override
    public String myMethod(String dostuff)
    {
      return dostuff + "One";
    }
  },
  myOtherValue
  {
    @Override
    public String myMethod(String dostuff)
    {
      return dostuff + "Two";
    }
  },
  aThirdValue
  {
    @Override
    public String myMethod(String dostuff)
    {
      return dostuff + "Three";
    }
  };

  public abstract String myMethod(String dostuff);
}

现在我们都可以认同这看起来很糟糕? 但是有更好的方法吗?我可以使用抽象工厂,但那样我需要三个实现类,每个类只有一行代码。我也不觉得那很漂亮。我可以使用 switch(无论是在代码中还是在枚举中)。但那样我可能会忘记添加一个 case。 那么,应该怎么做呢?肯定有一个模式适用于此,但我找不到。到目前为止,我想到的最好的方法是在 Netbeans 中添加注释以自动折叠方法,但那也不太好。

请发布您真正的需求 :-) - KLE
你可能需要重新撰写那个问题,以防止人们发布针对该特定琐碎示例的琐碎解决方案。 - skaffman
3个回答

8
解决方案是为枚举类创建一个私有构造函数:
public enum MyEnum
{
  myValue("One"), myOtherValue("Two"), aThirdValue("Three");

  private String value;

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

  public String myMethod(String dostuff)
  {
    return dostuff + value;
  }
}

注意,你可以传递更复杂的内容。例如,你可以传递一个实现了特定接口(比如说有一个方法 doWork()Work 类)的类。这种方式可以将方法调用存储在枚举中以完成不同类型的工作。
请查看命令模式或者策略模式

这是正确的做法。不幸的是,你比我快了几秒钟;-) - jens
是的,但是,虽然这对于这个简单的例子有效,但我的真实枚举并不简单。这些方法执行非常不同的操作。所以我不知道如何使用它。例如,如果我的方法调用两个其他方法,那该怎么办?那么我唯一能想到使用私有构造函数的方法就是使用反射来调用这些方法。但这并不美观。 - Mikael Sundberg
+1 你在我点击提交按钮之前就已经发布了你的答案;-) - KLE
@jens,KLE:是的,这些天在SO上有太多的人了 ;) - Aaron Digulla
@Mikael:请看我的修改。你可以传递任何东西到构造器中。在你的情况下,你正在寻找一种名为“命令模式”的设计模式(http://en.wikipedia.org/wiki/Command_pattern)。 - Aaron Digulla
@Aaron,我真的很喜欢你的编辑,关于使用共同接口的委托对象。谢谢。 - KLE

3

虽然看起来不太美观,但是对于这种非平凡问题的解决方案,大多数都只是在将丑陋的部分移到别处。

例如,您可以将三种不同的行为封装在某个接口的三个不同实现中,然后将不同的行为实现传递给每个枚举的构造函数。(这基本上是其他人建议的命令或策略方法)。

如果您将这些实现和接口作为单独的类进行处理,则可能会将该行为暴露到枚举之外,这是不必要的,而且可以说是丑陋的。

如果您将它们设置为枚举的私有静态内部类,则将丑陋的部分从文件顶部移动到文件底部。这样做是否更加美观取决于观察者的眼光。

public enum Foo {

    ONE(new OneDelegate()), 
    TWO(new TwoDelegate()),
    THREE(new ThreeDelegate());

    // ////////////////////
    // Private stuff

    private final FooDelegate delegate;

    private Foo(FooDelegate delegate) {
        this.delegate = delegate;
    }

    // ////////////////////
    // Public methods

    public String doStuff(String stuff) {
        return delegate.doStuff(stuff);
    }

    // ////////////////////
    // Helper classes

    private static interface FooDelegate {
        String doStuff(String stuff);
    }

    private static class OneDelegate implements FooDelegate {
        @Override
        public String doStuff(String stuff) {
            return "One " + stuff;
        }
    }

    private static class TwoDelegate implements FooDelegate {
        @Override
        public String doStuff(String stuff) {
            return "Two " + stuff;
        }
    }

    private static class ThreeDelegate implements FooDelegate {
        @Override
        public String doStuff(String stuff) {
            return "Three " + stuff;
        }
    }
}

另一个显而易见的解决方案是将所有三种行为作为私有方法放入,并在公共方法中加入 switch(this)。个人认为这很丑陋,但许多前C程序员似乎喜欢它。:)
public enum Foo {

    ONE, TWO, THREE;

    // ////////////////////
    // Public methods

    public String doStuff(String stuff) {
        switch(this) {
            case ONE:
                return doStuffOne(stuff);
            case TWO:
                return doStuffTwo(stuff);
            case THREE:
                return doStuffThree(stuff);

    // If we're handing all enum cases, we shouldn't need
    // a default (and per comments below, if we leave out
    // the default, we get the advantage that the compiler
    // will catch it if we add a new enum value but forget
    // to add the corresponding doStuff() handler

    //      default:
    //          throw new IllegalStateException("Who am I?");
        }
    }

    // ////////////////////
    // Static helpers

    private static String doStuffOne(String stuff) {
            return "One " + stuff;
    }

    private static String doStuffTwo(String stuff) {
            return "Two " + stuff;
    }

    private static String doStuffThree(String stuff) {
            return "Three " + stuff;
    }
}

1
不错的解决方案。但我想对最后一个方案添加一点小注释。如果你向枚举中添加了一个新元素,编译器并不会强制你去覆盖任何东西,在你调用那个新实例的 doStuff() 方法之前,你不会得到 IllegalArgumentException,这可能是一个潜在的 bug 来源,如果不小心使用的话。但我必须承认,从丑陋的角度来看,这是一个更好的解决方案。问题仍然存在,它是否应该成为考虑的有效点。 - Balázs Németh
很好的观点。如果您的 switch 语句包含了所有的情况,那么您就不需要一个默认值,最好是将其省略掉,让编译器来处理它。我会更新这个示例。 - David Moles

1

这个怎么样?

     public enum MyEnum {
         myValue("One"),
         myOtherValue("Two"),
         aThirdValue("Three");

        private final String postfix;
        private MyEnum(String postfix) {
          this.postfix )= postfix;
        }
        public String myMethod(String dostuff) {
          return dostuff + postfix;
        }
      }

即使您的实际内容更加复杂,也有几种技术可以实现这些改进。请发布您的真实需求...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接