Método de criação estática - prós e contras em comparação com construtores


11

Quais são os prós e os contras de ter métodos estáticos de criação de objetos sobre construtores?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Poucos em que consigo pensar:

Prós:

  • Retorne nulo em vez de lançar uma exceção (nomeie-a TryCreate). Isso pode tornar o código mais conciso e limpo no lado do cliente. Os clientes raramente esperam que um construtor falhe.
  • Crie diferentes tipos de objetos com semântica clara, por exemplo, CreatFromName(String name)eCreateFromCsvLine(String csvLine)
  • Pode retornar um objeto em cache, se necessário, ou uma implementação derivada.

Contras:

  • Menos detectável, mais difícil de ler o código.
  • Alguns padrões, como serialização ou reflexão, são mais difíceis (por exemplo Activator<Foo>.CreateInstance())

1
É mais lento. Você precisa manipular a referência nula de qualquer maneira.
Amir Rezaei

1
@Amir Handling null é ( Foo x = Foo.TryCreate(); if (x == null) { ... }). A manipulação de uma exceção de ctor é ( Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). Ao chamar um método normal, prefiro exceções a códigos de erro, mas com a criação de objetos, TryCreateparece mais limpo.
dbkk

Em sua validação, você faria alguma verificação de tipo?
Amir Rezaei

Com relação ao segundo Pro, "Crie tipos diferentes de objetos com semântica clara, por exemplo, CreatFromName (nome da string) e CreateFromCsvLine (String csvLine)", é melhor criar Namee CsvLinedigitar, em vez de expressar requisitos por meio de nomes de métodos. Isso permitiria sobrecarregar o Create. O uso de strings para ambos pode ser considerado uma "obsessão primitiva" (supondo que você não tenha feito essa escolha por motivos conhecidos de desempenho). Confira Object Calisthenics para uma maneira divertida de explorar isso.
precisa saber é o seguinte

Respostas:


7

A maior desvantagem dos ' criadores ' estáticos provavelmente está limitando a herança. Se você ou o usuário da sua biblioteca deriva uma classe da sua Foo, Foo::Create()torna - se praticamente inútil. Toda a lógica definida lá terá que ser reescrita novamente na herança Create().

Sugiro um compromisso: defina um construtor com lógica trivial de inicialização de objeto que nunca falha / atire, depois defina criadores com cache, construção alternativa etc. Isso deixa a possibilidade de derivar e você se beneficia de ter criadores para uma determinada classe .


1
Na prática, não é realmente um problema, porque a maioria das classes não é projetada para ser herdada (e, portanto, deve ser selada / final). Se, posteriormente, você desejar abrir a classe para herança, sempre poderá mover qualquer lógica de inicialização para um construtor protegido.
Doval

7

Criar é um método de fábrica. Quando sinto necessidade disso, implemento o padrão Factory e defino uma interface para representar o contrato para a criação do objeto, bem como uma classe de implementação, que é injetada quando necessário. Isso mantém as vantagens de mover a responsabilidade de criação para fora da classe, mas evita (ou pelo menos torna mais óbvia) as limitações de executar a criação de objetos fora do construtor da classe.

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.