Estoy trabajando en un código de interfaz de usuario donde tengo una Action
clase, algo como esto:
public class MyAction extends Action {
public MyAction() {
setText("My Action Text");
setToolTip("My Action Tool tip");
setImage("Some Image");
}
}
Cuando se creó esta clase de acción, se suponía que la Action
clase no sería personalizable (en cierto sentido, su texto, información sobre herramientas o imagen no se cambiarán en ninguna parte del código). Ahora, necesitamos cambiar el texto de acción en alguna ubicación del código. Entonces, le sugerí a mi compañero de trabajo que eliminara el texto de acción codificado del constructor y lo aceptara como argumento, para que todos se vean obligados a pasar el texto de acción. Algo como este código a continuación:
public class MyAction extends Action {
public MyAction(String actionText) {
setText(actionText);
setTooltip("My Action tool tip");
setImage("My Image");
}
}
Él, sin embargo, piensa que dado que el setText()
método pertenece a la clase base, se puede usar de manera flexible para pasar el texto de acción donde sea que se cree una instancia de acción. De esa manera, no hay necesidad de cambiar la MyAction
clase existente . Entonces su código se vería así.
MyAction action = new MyAction(); //this creates action instance with the hardcoded text
action.setText("User required new action text"); //overwrite the existing text.
No estoy seguro si esa es una forma correcta de lidiar con el problema. Creo que en el caso mencionado anteriormente, el usuario de todos modos va a cambiar el texto, entonces, ¿por qué no forzarlo mientras construye la acción? El único beneficio que veo con el código original es que el usuario puede crear la clase de acción sin pensar mucho en configurar el texto.
Respuestas:
Eso en realidad no es un beneficio, para la mayoría de los propósitos es un inconveniente y en los casos restantes lo llamaría un empate. ¿Qué pasa si alguien olvida llamar a setText () después de la construcción? ¿Qué pasa si ese es el caso en algún caso inusual, tal vez un controlador de errores? Si realmente desea forzar el ajuste del texto, debe forzarlo en el momento de la compilación, ya que solo los errores en tiempo de compilación son realmente fatales . Todo lo que sucede en tiempo de ejecución depende de la ruta de código particular que se ejecute.
Veo dos caminos claros hacia adelante:
null
o una cadena vacía, pero el hecho de que no está asignando un texto es explícito en lugar de implícito. Es fácil ver la existencia de unnull
parámetro y ver que probablemente haya pensó algo en él, pero no es tan fácil ver la falta de una llamada al método y determinar si la falta fue intencional o no. Para un caso simple como este, este es probablemente el enfoque que tomaría.fuente
La sobrecarga de constructores sería una solución simple y directa aquí:
Es mejor que llamar
.setText
más tarde, porque de esta manera no es necesario sobrescribir nada,actionText
puede ser lo que se pretende desde el principio.A medida que su código evoluciona y necesitará aún más flexibilidad (lo que seguramente sucederá), se beneficiará del patrón de fábrica / generador sugerido por otra respuesta.
fuente
Agregue un método fluido 'setText':
¿Qué podría ser más claro que eso? Si decide agregar otra propiedad personalizable, no hay problema.
fuente
setText()
se define en la clase de Acción de la que MyAction hereda. Es probable que ya tenga un tipo de retorno nulo.Tal como dijo Kevin Cline en su respuesta, creo que el camino a seguir es crear una API fluida . Solo me gustaría agregar que la API fluida funciona mejor cuando tiene más de una propiedad que puede usar.
Hará que su código sea más legible y, desde mi punto de vista, más fácil y, aham , "sexy" escribirlo.
En su caso, sería así (perdón por cualquier error tipográfico, ha pasado un año desde que escribí mi último programa Java):
Y el uso sería así:
fuente
El consejo para usar constructores o constructores está bien en general, pero, en mi experiencia, pierde algunos puntos clave para las Acciones, que
Sugiero encarecidamente que el nombre, la información sobre herramientas, el icono, etc. se lean desde un archivo de propiedades, XML, etc. Por ejemplo, para la acción Abrir archivo, puede pasar Propiedades y buscará
Este es un formato bastante fácil de traducir al francés, para probar un nuevo ícono mejor, etc. Sin tiempo de programador ni recompilación.
Esto es solo un esbozo, queda mucho para el lector ... Busque otros ejemplos de internacionalización.
fuente
Es inútil llamar a setText (actionText) o setTooltip ("Mi sugerencia de herramienta de acción") dentro del constructor; es más fácil (y gana más rendimiento) si simplemente inicializa el campo correspondiente directamente:
Si cambia actionText durante el tiempo de vida del objeto correspondiente MyAction, debe colocar un método setter; si no, inicialice el campo solo en el constructor sin proporcionar un método de establecimiento.
Dado que la información sobre herramientas y la imagen son constantes, trátelas como constantes; tener campos:
En realidad, al diseñar objetos comunes (no beans u objetos que representan estrictamente estructuras de datos) es una mala idea proporcionar setters y getters, ya que rompen la encapsulación.
fuente
Creo que esto es cierto si vamos a hacer una clase de acción genérica (como actualización, que se utiliza para actualizar Empleado, Departamento ...). Todo depende del escenario. Si se crea una clase de acción específica (como actualizar empleado) (se usa en muchos lugares de la aplicación - Actualizar empleado) con la intención de mantener el mismo texto, información sobre herramientas e imagen en cada lugar de la aplicación (para un punto de vista coherente). Por lo tanto, la codificación puede hacerse para texto, información sobre herramientas e imagen para proporcionar el texto, información sobre herramientas e imagen predeterminados. Aún para dar más flexibilidad, para personalizarlos, debe tener los métodos de establecimiento correspondientes. Teniendo en mente solo el 10% de los lugares, tenemos que cambiarlo. Tomar texto de acción cada vez del usuario puede causar texto diferente cada vez para la misma acción. Como 'Actualizar Emp', 'Actualizar Empleado', 'Cambiar Empleado' o 'Editar Empleado'.
fuente
Piense en cómo se usarán las instancias y use una solución que guíe, o incluso obligue, a los usuarios a usar esas instancias de la manera correcta, o al menos mejor. Un programador que use esta clase tendrá muchas otras cosas de las que preocuparse y pensar. Esta clase no debe agregarse a la lista.
Por ejemplo, si se supone que la clase MyAction es inmutable después de la construcción (y posiblemente otra inicialización), no debería tener un método de establecimiento. Si la mayoría de las veces usará el "Mi texto de acción" predeterminado, debería haber un constructor sin parámetros, más un constructor que permita un texto opcional. Ahora el usuario no necesita pensar en usar la clase correctamente el 90% del tiempo. Si el usuario generalmente debería pensar un poco en el texto, omita el constructor sin parámetros. Ahora el usuario se ve obligado a pensar cuando es necesario y no puede pasar por alto un paso necesario.
Si un
MyAction
instancia necesita ser mutable después de la construcción completa, entonces necesita un setter para el texto. Es tentador omitir la configuración del valor en el constructor (principio DRY - "No se repita") y, si el valor predeterminado es generalmente lo suficientemente bueno, lo haría. Pero si no es así, requerir el texto en el constructor obliga al usuario a pensar cuándo debería.Tenga en cuenta que estos usuarios no son tontos . Simplemente tienen demasiados problemas reales de los que preocuparse. Al pensar en la "interfaz" de su clase, también puede evitar que se convierta en un problema real, y uno innecesario.
fuente
En la siguiente solución propuesta, la superclase es abstracta y tiene los tres miembros establecidos en un valor predeterminado.
La subclase tiene diferentes constructores para que el programador pueda instanciarla.
Si se utiliza el primer constructor, todos los miembros tendrán los valores predeterminados.
Si se utiliza el segundo constructor, le da un valor inicial al miembro actionText dejando a otros dos miembros con el valor predeterminado ...
Si se utiliza un tercer constructor, lo instancia con un nuevo valor para actionText y toolTip, dejando imageURl con el valor predeterminado ...
Y así.
fuente