Estoy tratando de hacer que mi código sea más fácil de extender en términos de que un pequeño cambio no afectará mucho otro código.
Tengo una enumeración MyEnum , cuyos valores podrían aumentar en el futuro.
Luego, hay clases que tienen una instancia de él y tienen muchos comportamientos afectados por el valor concreto de esa enumeración . En otras palabras, hay muchos lugares donde cambio su valor.
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) { ... } } }La cuestión aquí es que, en su mayoría , tendré que agregar un nuevo caso a todos los lugares donde cambiamos su valor => necesitaré hacer muchos cambios en el código cuando agregue un nuevo valor de enumeración .
¿Alguien más se enfrentó a este problema? Por ahora, supongo que es solo una desventaja usar enum s de esta manera.
No vincule su código a la enum , vincule su código a una interfaz. Luego, haga que su enumeración proporcione las implementaciones estándar de la interfaz.
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; } } Tenga en cuenta que ahora puede agregar fácilmente una nueva lista de todos los Awards predeterminados al
Awards awards = new Awards(Arrays.asList(DefaultRibbonColors.values()));mientras que también puede crear conjuntos de premios personalizados.
List ribbons = new ArrayList<RibbonColor>(); ribbons.addAll(DefaultRibbonColors.values()); ribbons.addAll(ExtendedRibbonColors.values()); ribbons.addAll(new BlackAndPinkPolkaDotRibbonColor()); Awards awards = new Awards(ribbons); La clave es nunca hacer que el código realmente dependa de la enum porque no puede modificar una enum sin volver a compilar, y eso desencadena la necesidad de buscar declaraciones de switch que carezcan de valores default: bloques o configuraciones más explícitas para el valor agregado.
Los objetos son "código y datos escritos juntos", mientras que el código de procedimiento es "código y datos administrados por separado". La declaración switch coloca el "código" lógico fuera del tipo "datos" y es un error de programación en un diseño 100% increíblemente orientado a objetos. Dicho esto, a menudo es útil, y la gente todavía estructura los programas en Java y otros lenguajes de manera que efectivamente separan el código de los datos (objeto que contiene todos los datos y "rutinas de objeto" que manipulan los datos de otro objeto. Este tipo de separación de los datos de un objeto de sus rutinas es un antipatrón llamado anemic objects .
Enums son Objects , ¡así que no tenga miedo de ponerles métodos! Proporcione interfaces donde deberían ser replicables y evite las declaraciones de cambio porque probablemente sea una buena señal de que la lógica debería estar en lo que está activando (siempre que sea un Objeto).