2009-10-01 10 views
3

j'ai un ENUM qui ressemble àune des classes de méthode avec ENUM en java

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

Maintenant, je pense que nous pouvons tous convenir que cela semble horrible? mais quelle serait la meilleure façon? Je pourrais avoir une abstractfactory, mais alors j'aurais besoin de trois classes d'implémentation chacune en tant que méthode d'une ligne. Ne trouvez pas cela si joli non plus. Je pourrais utiliser un commutateur (soit dans le code ou dans l'énumération). Mais alors je pourrais oublier d'ajouter un cas.

Alors, quel est le chemin à parcourir? Il doit y avoir un modèle pour cela, mais je n'arrive pas à en trouver un. Le meilleur ive arriver jusqu'à présent est d'ajouter des commentaires pour agrandir les méthodes dans Netbeans, pas si brillant que non plus.

+0

S'il vous plaît poster votre besoin réel :-) – KLE

+0

Vous pouvez réécrire cette question pour décourager les gens affichant la solution triviale à cet exemple trivial spécifique. – skaffman

Répondre

3

Il est moche, mais la plupart des solutions aux extensions non-triviales du problème vont juste déplacer la laideur autour.

Par exemple, vous pouvez encapsuler les trois comportements différents dans trois implémentations différentes d'une interface, puis passer une implémentation de comportement différente au constructeur de chaque énumération. (C'est essentiellement l'approche de commandement ou de stratégie que d'autres suggèrent). Si vous faites ces implémentations, et l'interface, des classes distinctes, alors vous avez potentiellement exposé ce comportement au-delà de l'énumération, ce qui est inutile et peut-être moche. Si vous créez des classes internes statiques privées de l'enum, vous avez déplacé la laideur du haut du fichier au bas du fichier. Combien moins laid c'est dans l'oeil du spectateur.

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

L'autre solution évidente est de mettre tous les trois comportements dans les méthodes comme privées, et de mettre un switch(this) dans la méthode publique. Personnellement, je pense que c'est moche comme péché, mais beaucoup de programmeurs ex-C semblent l'aimer. :)

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

Belle solution. Je voudrais ajouter une petite remarque à la dernière cependant. Si vous ajoutez un nouvel élément à l'énumération, vous n'êtes pas obligé par le compilateur de redéfinir quoi que ce soit, et jusqu'à ce que vous appeliez 'doStuff()' sur cette nouvelle instance, vous n'obtiendrez pas ce 'IllegalArgumentException', et cela pourrait être un source d'un bug lorsqu'il n'est pas utilisé avec soin. Mais je dois convenir que du point de vue de la laideur c'est une meilleure solution. Des questions subsistent quant à savoir si cela devrait être un point de considération valable. –

+0

Bon point. Et puisque si votre instruction switch inclut tous les cas, vous n'avez pas besoin d'une valeur par défaut, il vaut mieux la laisser de côté et laisser le compilateur l'attraper. Je vais mettre à jour l'exemple. –

8

La solution est de créer un constructeur privé pour l'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] Notez que vous pouvez passer des choses plus complexes, par exemple, vous pouvez passer dans une classe qui implémente une certaine interface. (disons Work qui a une méthode doWork()). De cette façon, vous pouvez stocker des appels de méthode dans des énumérations pour effectuer différents types de travail.

Consultez le command pattern ou peut-être le strategy pattern.

+0

C'est la bonne façon de faire cela. Malheureusement vous étiez quelques secondes plus vite que moi ;-) – jens

+0

Oui, mais, alors que cela fonctionne pour cet exemple simple. Mon véritable énumération n'est pas aussi simple. Les méthodes font des choses assez différentes. Donc, je ne vois pas comment je pourrais utiliser cela alors. Que faire si par exemple ce que ma méthode fait est d'appeler deux autres méthodes?la seule façon dont je vois alors d'utiliser le constructeur privé est d'utiliser la réflexion pour appeler les méthodes. et ce n'est pas joli –

+0

+1 vous avez posté votre réponse avant que je clique sur le bouton soumettre ;-) – KLE

1

Qu'en est-il?

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

Même si votre vrai matériel est plus complexe, il existe plusieurs techniques qui permettent de telles améliorations. S'il vous plaît signaler votre besoin réel ...

Questions connexes