¿Usar el método constructor o setter?

16

Estoy trabajando en un código de UI donde tengo una clase Action , 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 asumió que la clase Action no será personalizable (en cierto sentido, su texto, información sobre herramientas o imagen no se cambiará en ninguna parte del código). Ahora, necesitamos cambiar el texto de acción en alguna ubicación del código. Por lo tanto, sugerí a mi compañero de trabajo que eliminara el texto de acción codificado del constructor y lo aceptara como un 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"); 
    }
}

Sin embargo, cree que, dado que el método setText() pertenece a la clase base, se puede utilizar de manera flexible para pasar el texto de acción donde se crea la instancia de acción. De esa manera, no es necesario cambiar la clase existente MyAction . Así que 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 de si esa es una forma correcta de tratar el problema. Creo que en el caso mencionado anteriormente, el usuario cambiará el texto, así que, ¿por qué no forzarlo mientras construimos la acción? El único beneficio que veo con el código original es que el usuario puede crear una clase de Acción sin pensar mucho en configurar el texto.

    
pregunta zswap 29.06.2012 - 07:18

9 respuestas

15
  

El único beneficio que veo con el código original es que el usuario puede crear una clase de Acción sin pensar mucho en configurar el texto.

Eso realmente 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 se olvida de 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 quieres forzar que el texto se establezca, debes forzarlo en el momento de la compilación, ya que solo los errores en tiempo de compilación son realmente fatales . Todo lo que ocurra en el tiempo de ejecución depende de la ruta del código en particular que se esté ejecutando.

Veo dos caminos claros hacia adelante:

  1. Use un parámetro de constructor, como sugiere. Si realmente lo desea, puede pasar 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 un parámetro null y ver que probablemente se haya puesto algún pensamiento en él, pero no es tan fácil ver la falta de una llamada de método y determinar si la falta de tal fue intencional o no Para un caso simple como este, este es probablemente el enfoque que tomaría.
  2. Usa un patrón de fábrica / constructor. Esto puede ser una exageración para un escenario tan simple, pero en un caso más general es muy flexible ya que le permite establecer cualquier número de parámetros y verificar las condiciones previas antes o durante la creación de instancias del objeto (si construir el objeto es una operación grande y / o la clase se puede usar de más de una manera, esto puede ser una ventaja enorme ). Particularmente en Java, también es un idioma común, y seguir los patrones establecidos en el lenguaje y el marco que está utilizando es muy raro que sea malo.
respondido por el a CVn 29.06.2012 - 10:01
10

La sobrecarga de constructores sería una solución simple y directa aquí:

public class MyAction extends Action {
    public MyAction(String actionText) {
        setText(actionText);
        setTooltip("My Action tool tip"); 
        setImage("My Image"); 
    }
    public MyAction() {
        this("My Action Text");
    }
}

Es mejor que llamar a .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 evolucione y necesitará aún más flexibilidad (lo que seguramente ocurrirá), se beneficiará del patrón de fábrica / constructor sugerido por otra respuesta.

    
respondido por el janos 29.06.2012 - 10:16
6

Agregue un método 'setText' fluido:

public class MyAction ... {
  ...
  public MyAction setText(String text) { ... ; return this; }
}

MyAction a = new MyAction().setText("xxx");

¿Qué podría ser más claro que eso? Si decide agregar otra propiedad personalizable, no hay problema.

    
respondido por el kevin cline 29.06.2012 - 19:19
1

Al igual que kevin cline dijo en su respuesta, creo que el camino a seguir es crear un 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 tu código sea más legible y, desde mi punto de vista, más fácil y, aham , "sexy" para escribir.

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):

 public class MyAction extends Action {
    private String _text     = "";
    private String _tooltip  = "";
    private String _imageUrl = "";

    public MyAction()
    {
       // nothing to do here.
    }

    public MyAction text(string value)
    {
       this._text = value;
       return this;
    }

    public MyAction tooltip(string value)
    {
       this._tooltip = value;
       return this;
    }

    public MyAction image(string value)
    {
       this._imageUrl = value;
       return this;
    }
}

Y el uso sería así:

MyAction action = new MyAction()
    .text("My Action Text")
    .tooltip("My Action Tool tip")
    .image("Some Image");
    
respondido por el Machado 17.08.2012 - 03:26
1

El consejo para usar constructores o constructores está bien en general, pero, según mi experiencia, omite algunos puntos clave para Acciones, que

  1. Posiblemente necesite estar internacionalizado
  2. Es probable que el marketing cambie a último momento.

Sugiero encarecidamente que el nombre, la información sobre herramientas, el icono, etc. se lean de un archivo de propiedades, XML, etc. Por ejemplo, para la acción Abrir archivo, puede pasar una Propiedades y buscará

File.open.name=Open
File.open.tooltip=Open a file
File.open.icon=somedir/open.jpg

Este es un formato bastante fácil de traducir al francés, para probar un nuevo icono mejor, etc. Sin tiempo de programador o una recompilación.

Esto es solo un resumen aproximado, queda mucho para el lector ... Busque otros ejemplos de internacionalización.

    
respondido por el user949300 07.08.2014 - 06:46
0

Es inútil llamar a setText (actionText) o setTooltip ("My action tool tip") dentro del constructor; es más fácil (y usted obtiene más rendimiento) si simplemente inicializa el campo correspondiente directamente:

    public MyAction(String actionText) {
        this.actionText = actionText;
    }

Si cambia actionText durante la vida útil del objeto correspondiente de MyAction, debe colocar un método de establecimiento; si no, inicialice el campo solo en el constructor sin proporcionar un método de establecimiento.

Como la información sobre herramientas y la imagen son constantes, trátelas como constantes; tener campos:

private (or even public) final static String TOOLTIP = "My Action Tooltip";

En realidad, cuando se diseñan objetos comunes (no beans u objetos que representan estructuras de datos estrictamente), es una mala idea proporcionar colocadores y captadores, ya que se rompen la encapsulación.

    
respondido por el m3th0dman 29.06.2012 - 08:12
0

Creo que esto es cierto si vamos a crear una clase de acción genérica (como actualizar, que se usa para actualizar Empleado, Departamento ...). Todo depende del escenario. Si se crea una clase de acción específica (como empleado de actualización) (utilizada 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 el punto de vista de la coherencia). Por lo tanto, se puede realizar una codificación para el texto, la información sobre herramientas y la imagen para proporcionar el texto, la información sobre herramientas y la imagen predeterminados. Aún para dar más flexibilidad, para personalizarlos, debe tener los métodos de establecimiento correspondientes. Teniendo en cuenta solo el 10% de lugares tenemos que cambiarlo. Tomar texto de acción cada vez que el usuario puede causar Texto diferente cada vez para la misma acción. Como 'Actualizar Emp', 'Actualizar empleado', 'Cambiar empleado' o 'Editar empleado'. No estoy seguro, pero creo que esto puede crear la confusión para el usuario de que esto es algo diferente.

    
respondido por el Sandy 29.06.2012 - 12:06
0

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 lo mejor. Un programador que use esta clase tendrá muchas otras cosas en las que preocuparse y en qué 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 "Texto de mi 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 para usar la clase correctamente el 90% del tiempo. Si el usuario normalmente debería reflexionar sobre 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 una instancia MyAction necesita ser mutable después de la construcción completa, entonces necesita un configurador para el texto. Es tentador omitir la configuración del valor en el constructor (principio DRY - "No se repita") y, si el valor predeterminado suele ser lo suficientemente bueno, lo haría. Pero si no lo es, exigir que el texto en el constructor obligue al usuario a pensar cuándo debería hacerlo.

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, puede evitar que se convierta en un problema real, y en uno innecesario.

    
respondido por el RalphChapin 29.06.2012 - 18:52
0

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 crear una instancia.

Si se usa el primer constructor, todos los miembros tendrán los valores predeterminados.

Si se usa el segundo constructor, le das un valor inicial al miembro actionText dejando a los otros dos miembros con el valor predeterminado ...

Si se usa el tercer constructor, se crea una instancia con un nuevo valor para actionText y toolTip, dejando a imageURl con el valor predeterminado ...

Y así sucesivamente.

public abstract class Action {
    protected String text = "Default action text";
    protected String toolTip = "Default action tool tip";
    protected String imageURl = "http://myserver.com/images/default.png";

    .... rest of code, I guess setters and getters
}

public class MyAction extends Action {


    public MyAction() {

    }

    public MyAction(String actionText) {
        setText(actionText);
    }

    public MyAction(String actionText, String toolTip_) {
        setText(actionText);
        setToolTip(toolTip_);   
    }

    public MyAction(String actionText, String toolTip_; String imageURL_) {
        setText(actionText);
        setToolTip(toolTip_);
        setImageURL(imageURL_);
    }


}
    
respondido por el Tulains Córdova 16.08.2012 - 16:13

Lea otras preguntas en las etiquetas