Como os padrões de projeto nos ajudam a melhorar? Strategy

Esta semana eu me deparei com um problema aparentemente difícil: usar uma mesma classe para ordenar diversos tipos de objetos.

Qual o contexto? A aplicação usa Zend Framework 2 e Doctrine, para quem não sabe ambos reforçam muito o uso do OO e principalmente, o doctrine segue especificações do JPA.

E nesse ínterim algumas coisas ficam difíceis de serem realizadas, como uma ordenação. Nossos nomes utilizam acento e por conta disso algumas funções de ordenação ficam malucas. Seguindo a dica do Vinicius73 (podem encher o saco dele a vontade) eu utilizei o pacote illuminate/support, do laravel. E mais ainda, seguindo os princípios do OO criei um novo método utilizando outro mediante um novo parâmetro:

Assim sendo quaisquer entidade que eu jogar na nesse método será ordenado mediante nomes em português. Como a entidade abaixo (apenas exemplificando — extraído do problema real):

Mas eis que surge o problema: tenho uma entidade que tem a propriedade nome, mas ela está agregada em outra entidade que não tem este atributo. Veja o exemplo abaixo:

Entidade com o atributo nome

Entidade sem o atributo nome, a qual agrega a entidade anterior.

Veremos o comportamento da ordenação:

Resultado:

Os nomes de usuários foram ordenados acentuadamente, mas a outra entidade não, simplesmente a entidade não tem o atributo nome, o que fazer? Preciso de algo para trazer este atributo nome, dinamicamente, para que a coleção seja ordenada. Vamos recorrer aos padrões de projeto.

Padrões de projeto são pequenas arquiteturas focadas em resolver problemas, neste caso, vamos usar o strategy, vejamos o que ele nos diz:

Qual o objetivo do Strategy pattern?

Alterar um algoritmo em tempo de execução apenas conhecendo sua interface. Segundo Erich Gamma (et all — Gamma, Erich et all. Padrões de projeto — Soluções reutilizáveis de software orientado a objetos. 2000, Bookman):

Definir uma família de algoritmos, encapsular cada uma delas e torná-las intercambiáveis. 
Strategy permite que o algoritmo varie independentemente dos clientes que o utilizam.

Aplicabilidade

Você necessita de variantes de um algoritmo. Por exemplo, pode definir algoritmos que refletem diferentes soluções de compromisso entre espaço/ tempo. As estratégias podem ser usadas quando essas variantes são implementadas como uma hierarquia de classes de algoritmos

Vantagens, desvantagens e consequências

Estratégias eliminam comandos condicionais da linguagem de programação. O padrão Strategy oferece uma alternativa ao uso de comandos condicionais para a seleção de comportamentos desejados. Quando diferentes comportamentos são agrupados em uma classe é difícil evitar o uso de comandos condicionais para a seleção do comportamento correto.O encapsulamento do comportamento em classes Strategy separadas elimina estes comandos condicionais.

A possibilidade de escolha de implementações. As estratégias podem fornecer diferentes implementações do mesmo comportamento. O cliente pode escolher entre estratégias com diferentes compromissos entre tempo e espaço.

Eu quero que qualquer entidade que entre na ordenação possa me devolver um objeto que me traga seu nome para ordenar. Cada entidade fará isto de maneira diferente, por estratégia diferente, ok, let’s code.

Primeiro criamos a interface apropriada:

Agora implementamos a interface nas entidades:

E definimos na collection que queremos objetos do tipo SortableName, observe a nova assinatura do método de nomes ASCII

Pronto, vamos testar? (Infelizmente o phpunit não tem este tipo de teste)

E o resultado?

Perceba que a entidade unidade integradora foi ordenada apenas por atributo unidade aula. Não fiz nenhum if ou switch. Nenhum método extra foi criado para cada objeto diferente. Nenhuma mudança brusca foi feita no código, apenas mudança de estratégia. ;)

Perceba também que neste cenário o strategy foi implementado de forma diferente dos catálogos, mas que atingiu o meu objetivo e o dele.

PS.: Eu poderia fazer a consulta ordenada ao banco, mas eu perderia o aspecto OO do contexto e resolver o problema de forma elegante.

PS. 2: Este é o repo.