¿Es un gran inicializador estático un olor a código?


8

Me estoy extendiendo SimpleExpandableListAdapteren Android. No creo que el adaptador de Android se implemente muy bien, ya que sus constructores tienen una gran cantidad de argumentos bastante complicados y no tiene configuradores ni creadores. En mi clase, la mayoría de esos argumentos no dependen de la clase de llamada, por lo que quiero construirlos internamente. Sin embargo, los argumentos son anidados Listsy arrays de ints y cadenas que deben construirse mediante programación.

Como no se puede invocar nada antes del superconstructor, y los métodos de instancia no se pueden superinvocar antes de que vuelva la llamada, actualmente tengo varios métodos estáticos a los que llamo desde la superllamada:

super(getContext(), initGroupData(), groupLayout, initGroupFrom(), initGroupTo(),
        initChildData(), childLayout, initChildFrom(), initChildTo());

Veo tres formas de manejar esto: llamar a métodos estáticos como ahora, tener un gran inicializador estático que probablemente llame a estos mismos métodos para inicializar variables estáticas que luego se usan en la superllamada, o encapsular todos estos métodos en un generador.

Creo que en este momento me estoy inclinando hacia el constructor, pero me pregunto si hay una mejor manera de manejar esto.


1
¿Qué pasa con un método / función de fábrica?
Paŭlo Ebermann

Respuestas:


9

Tener funciones auxiliares estáticas para crear el argumento del constructor es una solución perfectamente sensata, pero estas funciones están limitadas en las operaciones que pueden realizar, ya que deben producir exactamente un argumento cada una y no pueden comunicarse entre sí.

En el caso más general en el que desea adaptar una interfaz Constructor(A, B, C)a una interfaz más utilizable Constructor(X, Y), puede definir un constructor auxiliar privado que lleve un privado ArgumentObjecty encadene al constructor existente. El constructor más utilizable se encadena al constructor auxiliar mediante una función auxiliar estática para crear el objeto de argumento:

class Constructor {
  // constructor you want to wrap
  public Constructor(A a, B b, C c) { ... }
  // better constructor you are defining
  public Constructor(X x, Y y) { this(createArgumentObject(x, y)); }
  // helper constructor using an ArgumentObject
  private Constructor(ArgumentObject ao) { this(ao.a, ao.b, ao.c); }
  // helper to create the argument object
  private static ArgumentObject createArgumentObject(X x, Y y) { ... }
  private static class ArgumentObject { ... }
}

En lenguajes que no tienen encadenamiento de constructor dentro de la misma clase (como C ++ 03), tendría que definir una subclase intermedia para el constructor auxiliar.

Sin embargo, esta técnica es simplemente una generalización de su uso de funciones estáticas en los argumentos del constructor. Las otras soluciones que ha propuesto tienen varios inconvenientes, por lo que los evitaría a menos que haya una muy buena razón para preferirlos:

  • implementar buenos constructores requiere mucho esfuerzo por muy poco valor. Si el nuevo constructor es lo suficientemente simple, puede prescindir de un constructor. Suponiendo que la clase que está ajustando realiza una validación sólida, puede hacer público el objeto de argumento para que los argumentos puedan pasarse utilizando el Constructor(new Constructor.Arguments {{ foo = 42; bar = baz; }})idioma.

  • el uso de variables estáticas que se calculan en un bloque inicializador estático tiene sentido para datos verdaderamente estáticos, pero se debe tener cuidado para evitar el estado global. A menos que la inicialización sea muy simple, debe usar funciones estáticas para inicializar estas variables para que la inicialización sea comprobable. Ahora, la única ventaja sobre el uso directo de métodos estáticos es que los valores solo se calculan una vez y se reutilizan para todas las inicializaciones.

    Como su pregunta indica que estas inicializaciones podrían ser más complejas, el uso de bloques inicializadores estáticos es un gran no-no si la capacidad de prueba es importante para usted. (Si no es así, tiene problemas más urgentes).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.