Onde devo colocar um método que retorna uma lista de entradas ativas de uma tabela?

5

Eu tenho uma classe chamada GuestbookEntry que é mapeada para as propriedades que estão na tabela de banco de dados chamada "guestbook". Muito simples!

Originalmente, eu tinha um método estático chamado getActiveEntries() que recuperava uma matriz de todos os objetos GuestbookEntry . Cada linha na tabela de guestbook era um objeto que foi adicionado a essa matriz. Então, enquanto aprendia a projetar classes PHP corretamente, aprendi algumas coisas:

  1. Métodos estáticos não são desejáveis.
  2. Separação de dúvidas
  3. Princípio da responsabilidade única

Se a classe GuestbookEntry deve ser responsável apenas pelo gerenciamento de entradas de livro de visitas, onde deve esse método getActiveEntries() ser usado?

Atualização:

Estou à procura de uma resposta que esteja em conformidade com os princípios de acrônimo SOLID e permita a capacidade de teste. É por isso que quero ficar longe de chamadas estáticas / funções padrão.

DAO, repositório, ...? Por favor, explique como se sua explicação fosse parte de "Where to Locate FOR DUMMIES" ...: -)

    
por darga33 04.11.2012 / 02:26
fonte

6 respostas

0

Este caso de uso exige um objeto de acesso a dados (DAO) , que lida com a responsabilidade de recuperar objetos do subjacente armazenamento de dados.

Por exemplo, você pode definir um GuestbookEntryDao com métodos como getById(...) , getActiveEntries(...sort options...) , etc.

Edit: Em resposta ao seu comentário:

GuestbookEntryDao seria uma interface implementada por uma classe MySqlGuestBookEntryDao , aproximadamente. O ponto é que você pode alternar as implementações (queda em uma classe FlatXmlGuestBookEntryDao ) sem afetar o restante do aplicativo.

GuestbookEntry não estenderá GuestbookEntryDao , e IMHO não deverá não depender disso (embora algumas pessoas discordem): Elas devem ser objetos separados inteiramente, porque há duas responsabilidades separadas em jogo (o modelo e as responsabilidades de acesso a dados).

O resultado é que, em algum lugar do seu aplicativo, você terá um processo de alto nível representando um caso de uso de seu aplicativo que pode ser parecido com (pseudo-código):

function browseGuestBook() {

    // ... determine which entries to retrieve ...

    // retrieve entries
    entries = guestBookEntryDao.getActiveEntries(...);

    // store entries in output model
    // (this part may vary wildly depending on your app)
    guestbookBrowserOutput.entries = entries;

    // ...

}

As classes em que tais funções / processos residem são geralmente chamadas de serviços em projeto orientado a domínio ( Estou me referindo a um serviço de nível de aplicativo, neste caso, não um serviço de domínio). Este objeto dependerá de GuestbookEntryDao para recuperar as entradas necessárias; GuestbookEntry não sabe que GuestbookEntryDao existe.

Isso também se refere à injeção de dependência e ao fornecimento de objetos com as referências de que precisam para fazer seu trabalho - nada mais e nada menos -, mas esse é um tópico diferente ...

    
por 04.11.2012 / 05:25
fonte
1

Onde você aprendeu que os métodos estáticos não são desejáveis? Eu tenho uma pergunta para você: quantas guestbook tabelas você tem? Obviamente, você só tem 1.

Às vezes, faz muito sentido usar uma função antiga simples ou um método estático para realizar meta-operações que são um "nível acima".

Algumas pessoas defendem uma GuestbookEntryCollection de classe que gerencia um conjunto de GuestBookEntry de objetos, mas ...

... aqui é onde o purismo contra o pragmatismo entra em jogo.

Se tudo que você precisa é de uma lista de GuestBookEntry objetos, então coloque esse código em um callable (seja uma função, ou método estático), e simplesmente chame-o.

Você precisa de recursos avançados, como criar uma consulta personalizada, classificá-los, filtrá-los, etc ...? Talvez isso garanta uma classe separada para administrá-lo.

Qual é a diferença entre objetos e funções? Objetos podem manter o estado individual, enquanto as funções são sem estado. Se você está executando operações funcionais e não tem estado para gerenciar, então as funções são ótimas!

Aqui está outra coisa a considerar ... No PHP, as funções precisam ser incluídas manualmente antes que possam ser usadas, mas as classes têm a capacidade de fazer o carregamento automático.

include('/path/to/function.php')
$x = GuestbookEntryList()

vs.

$x = GuestbookEntry::GetList()

vs.

$x = new GuestbookEntryCollection()

Alimento para o pensamento:)

    
por 04.11.2012 / 03:41
fonte
0

Veja como eu faria isso. Para dados de linha, basta usar arrays, então:

$entry = array(
    'entry_id' => '23',
    'user_id' => '4',
    'creation_date' => '2012-11-03',
    'content' => 'blah blah.');

Suas chamadas de modelo de banco de dados retornarão dados de linha no formato acima - é também como os plugins de banco de dados PHP retornam dados para que você não precise fazer nada. Então, para obter os dados, basta ter um objeto de modelo:

class EntryModel {
    public function getEntries() {
        //
    }

    public function getEntry($entryID) {
        //
    }
}

Então, como você pode ver, não importa se você está recebendo uma única entrada ou um monte de entradas - apenas faça o seu método retornar o conjunto de dados desejado.

    
por 04.11.2012 / 04:08
fonte
0

Como você provavelmente está em busca de um tipo de resposta purism , e não apenas sobre o que funcionaria, o Guestbook nem deveria depender um banco de dados.

Em vez disso, você tem um Guestbook , você tem um Database e você tem um GuestbookGateway . O gateway recupera linhas do banco de dados na forma de objetos PHP, e quando algo precisa ser alterado, o gateway tem um método save que aceita Guestbook . Essa é uma separação adequada de preocupações.

O ORM pode levar a muitos problemas a partir do acoplamento rígido em que se baseia. Eu tive que lidar com alguns deles no passado, e não foi bonito. No entanto, deve-se notar que, para muitos aplicativos (especialmente aplicativos da Web que geralmente funcionam da mesma maneira), o ORM é bom o suficiente.

    
por 04.11.2012 / 06:14
fonte
0

Pessoalmente eu iria para uma classe, 'Guestbook', que contém a matriz de GuestbookEntries e tem a função como um membro dessa classe. A função ainda pode retornar uma matriz de entradas conforme desejado.

    
por 05.11.2012 / 01:37
fonte
0

Se eu entendi sua pergunta corretamente ...

você está procurando pelo lugar "correto" para colocar o método getActiveEntries (). Porque a partir de um "ponto de vista" do OO-Design, você quer aderir aos princípios de:

  • Separação de dúvidas
  • Princípio da responsabilidade única

(FYI: Eu nunca ouvi evitar a estática, então eu pulei essa)

A causa do seu "problema" :

Cada entrada só deve se preocupar consigo mesma e ser responsável por si mesma. Portanto, não pode ser responsável por uma "coleção" de entradas.

Os princípios que você mencionou acima são princípios orientados a objetos. Soluções para problemas envolvendo princípios OO exigem que você crie muitos objetos e muitas classes para que juntos funcionem como uma solução.

Agora, se o método "getEntries" não puder entrar na classe DAO (Data Access Object),

... poderia entrar em um tipo de classe de fábrica. A Factory é responsável por "criar" objetos. Você poderia argumentar que uma Factory for GuestBookEntries tem 2 métodos: createEntryFromId (int $ entryId) e createActiveEntries ().

... poderia entrar em um tipo de classe de controlador. O mesmo que a fábrica acima, apenas chamado de forma diferente. O tipo de classe de controlador poderia fazer qualquer coisa, até mais que uma fábrica. Se você precisar de algo como "verify ()" ou "isDirty" para seu GuestBookEntry, a fábrica não seria mais o local para colocar esses métodos. Porque as fábricas só estão preocupadas com a criação (elas meio que têm o dever de garantir a criação ou falhar rapidamente), onde o tipo de classe de controlador pode carregar os métodos verify () ou isXYZ () sem ferir seu "propósito".

... no final, não importa o que você chama de "isso". Mas você precisará de outra "classe / objeto" para assumir a responsabilidade de restaurar uma coleção de GuestBookEntries ativos. O mais provável é que essa classe faça uso da única classe GuestBookEntry que você já possui.

Quando tivermos que implementar os métodos que interagem uns com os outros (a nova classe e o GuestBookEntry), você pode usar array () como um contêiner para transportar objetos GuestBookEntry. Você pode criar um contêiner "tipado" especial que garanta o transporte apenas de objetos GuestBookEntry, mas isso depende de você. (Mais ainda outra decisão de design, hehe)

Para resumir:

Crie outra classe com a responsabilidade de recuperar "coleções de GuestBookEntries com base em seu status (ativo | inativo)" que usa (composição) sua classe GuestBookEntry existente.

    
por 06.11.2012 / 11:55
fonte