Implementação do padrão de repositório que não sabe nada sobre os nomes da tabela e da coluna do banco de dados

5

Eu já vi na Internet e no Github implementações para o Repositório de padrão de design que conhece nomes de tabelas e colunas de banco de dados. Eu estava pensando, se eu quisesse trabalhar com o banco de dados como um plugin, que eu poderia desconectar e plugar outro respeitando Open / Closed para o resto do meu código, meu repositório não deveria saber sobre os nomes das colunas do banco de dados que estou usando . Então, como implementar esse padrão de uma maneira que ele possa transformar o resultado do banco de dados em uma Entidade do meu domínio, sem conhecer os nomes de tabela e coluna do banco de dados?

Como minha linguagem principal é PHP, vi que no Doctrine \ ORM você pode facilmente passar diferentes yamls ou arquivos de configuração xmls, mapeando os nomes das colunas para nomes de propriedades na Entity, mas ... eu não posso ser refém de um implementação da biblioteca, se eu quiser implementar o PDO bruto, ou qualquer outra biblioteca para meus repositórios que não torne essa hidratação pronta, minha implementação deveria fazer, então como?

Atualizar

Atualização 2
Por favor, dê uma olhada: link

    
por Leo Cavalcante 08.07.2014 / 17:28
fonte

2 respostas

3

O que você está falando aqui é inversão de dependência e encapsulamento. Você está consumindo código quer manter uma dependência de algum meio de se apossar de entidades de domínio, sem precisar saber como isso acontece. Ele quer um conjunto de métodos em uma caixa preta, que espera fornecer algumas entradas e obter algumas saídas: uma interface.

Em vez de ter seu código dependente de alguma implementação concreta de acesso a dados, você depende de uma abstração: a interface. Contanto que seu código de chamada saiba apenas sobre a abstração, não importa como você preenche essa interface, contanto que você a faça corretamente.

Analisando os exemplos do Doctrine e do PDO bruto da sua pergunta, você pode definir uma interface como:

interface FooRepositoryInterface {
    public function getAFoo($id);
}

Com a interface pronta, você pode implementá-la da maneira que achar melhor:

public class DoctrineFoo implements FooRepositoryInterface {
    public function __construct(EntityManager $em){ ... }
    public function getAFoo($id){ 
        return $this->em->find("\Entity\Foo", $id);
    }
}

public class PDOFoo implements FooRepositoryInterface {
    public function __construct(PDO $pdo){ ... }
    public function getAFoo($id){ 
        $pdo->prepare("sql ...");
        $row = $pdo->fetchOne();
        return $this->makeFooFromRow($row);
    }     
}

Isso permite que seus outros módulos dependam alegremente do acesso aos dados em termos da interface:

class FooBazer {
    public function doBaz(FooRepositoryInterface $repository, $id) {
        $foo = $repository->getAFoo($id);
        $foo->baz();
    }
}
    
por 08.07.2014 / 17:45
fonte
3

O propósito do repositório é fornecer um adaptador em torno do banco de dados. Ele "conhece o banco de dados", então o resto do seu código não precisa.

Portanto, parece-me bastante razoável que, se você alterar o esquema do seu banco de dados, você terá que alterar (ou substituir) os seus repositórios. O ponto é que você somente tem que substituir os repositórios, porque a implementação é escondida do aplicativo pela interface.

Se você tiver muitos agregados e um repositório para cada um deles, para substituí-los por atacado é difícil, talvez você possa obter ajuda de um ORM, dependendo das tecnologias que estiver usando. Um Repository<T> genérico parece ser bastante comum em C #, por exemplo.

É claro que, mesmo se você estiver usando um ORM, ainda precisa haver algum código, em algum lugar, que conheça o esquema do banco de dados. Mas, desta forma, normalmente está escondido em um arquivo de mapeamento XML (que, claro, tem suas próprias vantagens e desvantagens).

Editar em resposta aos seus comentários:

Eu realmente não vejo o que você está tentando alcançar. Em seu design, parece que os objetos 'Hidratação' assumem a responsabilidade de se comunicar com o banco de dados e retornar um objeto de domínio. Portanto, se você alterar o esquema do banco de dados, ainda precisará alterar todos os objetos de Hidratação. Sua proposta não resolve seu problema percebido: tem que haver algum código em algum lugar que saiba sobre o esquema do banco de dados.

Mas o seu design é muito mais complicado: existe uma camada extra (o próprio repositório) que basicamente não faz nada.

public class FooRepository
{
    private IFooHydration _fooHydration;

    public FooRepository(IFooHydration fooHydration)
    {
        _fooHydration = fooHydration;
    }

    public Foo Get(int id)
    {
        return _fooHydration.Get(id);
    }

    public void Save(Foo entity)
    {
        _fooHydration.Save(entity);
    }
}

É muito mais simples usar um IRepository e gravar implementações diferentes para seus diferentes métodos de persistência. Em suma, o repositório é o que você plug-in quando você altera bancos de dados.

    
por 11.07.2014 / 00:21
fonte