tags:

views:

126

answers:

3

I have an enum that looks like

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

Now I think we can all agree that this looks horrible? but what would be the bether way? I could have an abstractfactory, but then i would need three implementationclasses that each as a one line method. Dont find that so pretty either. I could use a switch (either in the code or in the enum). But then i could forgett to add a case.

So, whats the way to go? There must be a pattern for this, but cant seem to find one. The best ive come up with so far is to add comments to autocollapse the methods in Netbeans, not so brilliant that either.

+8  A: 

The solution is to create a private constructor for the enum:

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

[EDIT] Note that you can pass more complex things in. For example, you can pass in a class which implements a certain interface (say Work which has a method doWork()). This way, you can store method calls in enums to do different kinds of work.

Check out the command pattern or maybe the strategy pattern.

Aaron Digulla
That's the right way to do this. Unfortunately you were some seconds faster than I was ;-)
jens
Yes, but, while that works for this simple example. My real enum isnt as simple. The methods do pretty different things. So I dont see how i could use this then. What if for example what my method does is call two other methods? the only way i see then to use the private constructor is to use reflection to call the methods. and that doesnt feel pretty
Mikael Sundberg
+1 you posted your answer before I clicked on the submit button ;-)
KLE
@jens, KLE: Yeah, there are just too many people on SO these days ;)
Aaron Digulla
@Mikael: See my edits. You can pass arbitrary things to the constuctor. In your case, you're looking for a design pattern called Command (http://en.wikipedia.org/wiki/Command_pattern)
Aaron Digulla
@Aaron I really like your EDIT, concerning the delegation objects with a common interface. Thanks.
KLE
+1  A: 

What about?

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

Even if your real stuff is more complex, there are several techniques that allow such improvements. Please post your real need...

KLE
+1  A: 

It's ugly, but most solutions to non-trivial extensions of the problem are just going to move the ugliness around.

For instance, you could encapsulate the three different behaviors in three different implementations of some interface, and then pass a different behavior implementation to the constructor of each enum. (This is basically the command or strategy approach that others are suggesting).

If you make these implementations, and the interface, separate classes, then you've potentially exposed that behavior beyond the enum, which is unnecessary and arguably ugly.

If you make them private static inner classes of the enum, you've moved the ugliness from the top of the file to the bottom of the file. How much less ugly this is is in the eye of the beholder.

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

The other obvious solution is to put all three behaviors in as private methods, and put a switch(this) in the public method. Personally, I think this is ugly as sin, but a lot of ex-C programmers seem to like it. :)

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);
      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;
    }
}
David Moles