A estática é ruim, mas e o padrão de fábrica?

13

Estou em um projeto de TDD, então tento manter o máximo possível as boas práticas envolvidas com esse tipo de desenvolvimento. Uma delas é evitar o máximo possível de estática e global.

Estou enfrentando esse problema: tenho um objeto "artigo" que pode ter "opções" ("micro-artigos" adicionais) vinculados a ele.

Não consigo descobrir como ter uma boa abordagem que não seja contraproducente ou gere muitas consultas, porque eu estaria em uma situação em que tudo está tão dissociado que basicamente precisarei fazer 1 consulta por objeto.

Da minha perspectiva real, vejo três opções:

1) Construa o artigo interno:

class Article
{
    //[...]
    public function getArrOption(){
        //Build an array of Options instance.
        //return an array of Options.
    }
}

Pro: direto

Const: Manutenção: O objeto de artigo agora contém a lógica de construção do objeto Opção. Isso provavelmente levará à duplicação de código.

2) Usando um optionFactory

class Article
{
    //[...]
    public function getArrOption(){
        return OptionFactory::buildFromArticleId($this->getId());
    }
}

Pro: a lógica de construção não está fora da classe Article

Const: estou violando a regra "estática é difícil de zombar", dificultando o teste da minha classe Article.

3) Separe todas as lógicas.

//Build the array of Option instance in a controller somewhere, using a Factory:
$arrOption = OptionFactory::buildFromArticleId($article->getId());

Pro: o artigo lida apenas com sua própria responsabilidade e não se importa com o link "pai" para as opções. As coisas estão realmente dissociadas

Const: exigirá mais código dentro do Controller toda vez que precisar acessar as Opções. Isso significa que eu nunca deveria usar uma fábrica dentro de um objeto, e isso me parece utópico ...

Qual o melhor caminho a percorrer? (Perdi alguma coisa?) Obrigado.

Editar:

Sem mencionar que, se eu não posso ligar para a fábrica dentro da classe, basicamente também nunca posso usar o padrão de inicialização lenta ...

FMaz008
fonte
Não tenho certeza se é pertinente, mas estou codificando em PHP, portanto, o "aplicativo" é menos estado. Precisamos recarregar todos os dados entre cada página, se não estiverem armazenados em um cookie de sessão. Isso significa que não podemos pré-carregar tudo como em uma linguagem de aplicativo.
FMaz008
@job: Bem, é porque é impossível substituir uma chamada estática dentro de um método durante o teste de unidade. O objetivo é usar injeção de dependência. Mas uma fábrica é geralmente estática, portanto não pode ser injetada.
precisa saber é o seguinte

Respostas:

12
  1. A estática não é "ruim", é imbatível. Você ainda pode usá-lo onde zombar não faz sentido.

  2. Esse não é um padrão de Fábrica, parece um padrão de Repositório, embora possa não ser. O Factory é onde você tem várias classes com a mesma interface / classe base e deseja separar a lógica que decide qual classe retornar. O repositório obtém os dados de seu repositório, abstraindo a implementação desse repositório (o Artigo não precisa saber se suas opções estão armazenadas no mesmo banco de dados, outro, um arquivo XML, um arquivo CSV, qualquer que seja).

  3. Você ignorou a possibilidade de atribuir à classe Article um objeto ObjectFactory (ou Repository, ou qualquer outra coisa) no construtor no qual ela pode chamar o método buildFromArticle.

Meu PHP está enferrujado, mas acho que fica assim:

class Article
{
    private $_option_repository;

    public function __construct($option_repository) {
        $_option_repository = $option_repository;
    }

    //[...]

    public function getArrOption(){
        return $_option_repository->buildFromArticleId($this->getId());
    }
}

Eu acho que isso preenche todos os seus profissionais acima.

pdr
fonte
Então, não há problema em ter instâncias do Factory / Repository / Mapper? Vou precisar de um contêiner de dependência ou algo assim, porque, se precisarmos injetar todo o factory / repository / mapper para todo o objeto possível que pode ser retornado por um objeto, isso rapidamente resultou muito. (Artigo -> OptionGroup -> Opção -> artigo, etc ..)
FMaz008
1
É mais do que ok, é preferível. Geralmente reservo o uso estático para remover o código repetido, onde é pequeno o suficiente para ser testado em várias classes. E sim, um contêiner do COI / DI facilitará sua vida muito. Use um.
Pdr7
1

Aqui está uma citação de artigo que argumenta que você nunca precisa de métodos estáticos, que fábricas abstratas demonstraram ser confusas e sugere uma ligeira mudança de linguagem em relação à injeção de dependência como solução.

O forte acoplamento entre instâncias e suas classes quebra o encapsulamento e, junto com a visibilidade global dos métodos estáticos, complica o teste. Fazendo da injeção de dependência um recurso da linguagem de programação, podemos nos livrar completamente dos métodos estáticos. Empregamos as seguintes alterações semânticas:

(1) Substitua toda ocorrência de um global por um acesso a uma variável de instância;

(2) Permita que a variável de instância seja injetada automaticamente no objeto quando for instanciada.

"Seuss: dissociando responsabilidades de métodos estáticos para configurabilidade refinada"

Wayback Machine Link

nes1983
fonte
3
Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada.
Gd