Um inicializador estático grande é um cheiro de código?


8

Estou estendendo SimpleExpandableListAdapterno Android. Não acho que o adaptador do Android seja implementado muito bem, pois seus construtores têm um grande número de argumentos bastante complicados e ele não possui criadores ou construtores. Na minha classe, a maioria desses argumentos não depende da classe de chamada, então eu quero construí-los internamente. No entanto, os argumentos são aninhados Liste matrizes de ints e strings que precisam ser construídos programaticamente.

Como nada pode ser chamado antes do superconstrutor e os métodos de instância não podem ser chamados antes do superretorno da chamada, atualmente tenho vários métodos estáticos que chamo da superchamada:

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

Eu vejo três maneiras de lidar com isso: chamar métodos estáticos como eu sou agora, ter um grande inicializador estático que provavelmente chama esses mesmos métodos para inicializar variáveis ​​estáticas que são usadas na superchamada ou encapsular todos esses métodos em um construtor.

Acho que agora estou me inclinando para o construtor, mas estou me perguntando se há alguma maneira melhor de lidar com isso.


1
Que tal um método / função de fábrica?
Paŭlo Ebermann

Respostas:


9

Ter funções auxiliares estáticas para criar o argumento do construtor é uma solução perfeitamente sã, mas essas funções são limitadas em quais operações elas podem executar, pois devem produzir exatamente um argumento cada e não podem se comunicar.

No caso mais geral em que você deseja adaptar uma interface Constructor(A, B, C)a uma interface mais utilizável Constructor(X, Y), é possível definir um construtor auxiliar particular que leva um privado ArgumentObjecte acorrenta ao construtor existente. O construtor mais utilizável acorrenta ao construtor auxiliar através de uma função auxiliar estática para criar o 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 { ... }
}

Em linguagens que não têm encadeamento de construtor na mesma classe (como C ++ 03), você teria que definir uma subclasse intermediária para o construtor auxiliar.

No entanto, essa técnica é apenas uma generalização do uso de funções estáticas nos argumentos do construtor. As outras soluções que você propôs têm várias desvantagens, e é por isso que eu as evito, a menos que haja uma boa razão para preferi-las:

  • implementar bons construtores exige muito esforço por muito pouco valor. Se o novo construtor for bastante simples, você poderá ficar sem um construtor. Supondo que a classe que você está agrupando realiza validação sólida, você pode tornar público o objeto de argumento para que os argumentos possam ser transmitidos usando o Constructor(new Constructor.Arguments {{ foo = 42; bar = baz; }})idioma.

  • o uso de variáveis ​​estáticas calculadas em um bloco inicializador estático faz sentido para dados realmente estáticos, mas é preciso ter cuidado para evitar o estado global. A menos que a inicialização seja muito simples, você deve usar funções estáticas para inicializar essas variáveis ​​para que a inicialização seja testável. Agora, a única vantagem sobre o uso direto de métodos estáticos é que os valores são calculados apenas uma vez e reutilizados para todas as inicializações.

    Como sua pergunta indica que essas inicializações podem ser mais complexas, o uso de blocos estáticos de inicialização é um grande não-não se a testabilidade for importante para você. (Caso contrário, você tem problemas mais urgentes.)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.