Padrões de Projeto - msfernandes/busine.me GitHub Wiki
###Consumo da API
Consumir os recursos de uma API RestFUL é uma tarefa repetitiva, onde, para cada recurso, o algorítmo é o mesmo:
- Acessar a URL do recurso
- Transformar o JSON da resposta em objetos Python
- Retornar uma lista com os objetos
Entretanto, a forma com que o JSON é transformado em objeto pode variar de acordo com o recurso. Busline, por exemplo, possui em seus atributos outras models (Company e Terminal), que chegam por meio do mesmo JSON e também devem ser transformados em objetos, fazendo com que a implementação não seja exatamente igual, apesar do algorítmo ser o mesmo dos outros recursos.
Para resolver esse problema, foi adoto o padrão Template Method, onde definimos:
- os métodos all() e filter() como os métodos templates
- os métodos url() e api_model() como métodos abstratos, que devem ser implementados para cada recurso
- os métodos get_list(json) e json_to_object(json, clz) como métodos que podem ser sobrescritos, mas possuem um comportamento padrão.

Ainda dentro do contexto do consumo da API, temos outro problema: uma API com muitos recursos significa que teremos muitas classes para consumir essa API! Portanto, seria interessante centralizar todas as formas de consumo em uma só classe. Para isso, utilizamos o padrão Facade, onde a classe BusinemeAPI centraliza todas as formas de consumo da API: atualmente, CompanyAPI, BuslineAPI e TerminalAPI.

###Confiabilidade do Sistema
Para garantir o funcionamento de algumas das funcionalidades do sistema, concluímos que era necessário haver redundância de dados, utilizando um banco de dados local e uma API RestFUL. Mas o problema encontrado foi, justamente, saber quando buscar os dados no banco o local e quando buscar os dados na API remota.
Para isso, utilizamos o padrão Adapter, onde teremos uma classe BusinemeModel, que conterá um conjunto de métodos que servirão de interface padronizada com a camada de persistência. As outras models do sistema irão herdar as características de BusinemeModel e irão implementar os métodos de consulta, que podem ou não buscar do banco local, tendo como ordem de prioridade a consulta à API, caso não seja possível, a consulta ao banco local.
O diagrama abaixo exemplifica o padrão Adapter, usando a model Busline.
###Rankeamento de Usuário
Para conseguir determinar um momento em que o usuário fosse rankeado no nosso sistema, utilizamos o padrão Observer.
Este padrão de projeto consiste em ter um "observador" que monitora uma determinada ação e notifica quem estiver de "ouvinte" para esta ação. Com isso, fizemos uso dos sinais do Django, que fazem o papel do Observer, definindo calculate_position como Listener para quando houver atualização ou criação de usuários, onde a partir da pontuação que este usuário possui, é possível definir um ranking.
O trecho de código abaixo demonstra nosso uso do padrão Observer: