Então, esse tipo de coisa parece ser meio roia e sem noção no começo, por que basicamente é um projeto inicial e pequeno para maioria dos casos.
Design patterns começam a fazer sentido quando o projeto começa a crescer e você precisa de determinada utilidade que só o uso da linguagem em si é capaz de prover.
Por exemplo que o Filipe Deschamps usa no vídeo dele que é interessante, é o caso de testes onde você não pode subir um "banco de dados real" para testar teu código, então a injeção de dependência cria um falso para "substituir o banco de dados" e então confirmar que o software funciona perfeitamente.
Outro que vou pegar diretamente do blog AkitaOnRails é o caso do porque o strategy é usado.
Digamos que temos as entidades Voyage e Cargo, tipo viagem e mercadoria, onde uma viagem tem muitas mercadorias. O Eric descreve um sistema que tem responsabilidade de associar cada mercadoria com uma viagem, gravar e rastrear esse relacionamento. Até aqui tudo bem. Em algum lugar do código vamos ter um método como esse:
public int makeBooking(Cargo cargo, Voyage voyage) {
int confirmation = orderConfirmationSequence.next();
voyage.addCargo(cargo, confirmation);
return confirmation;
}
Mas porque existem cancelamentos de última hora, uma prática padrão da indústria de entrega é aceitar mais mercadorias do que é possível numa única viagem. É o que se chama de "overbooking". Algumas vezes é usado um percentual simples, como 110% da capacidade, em outros casos tem regras mais complexas.
Isso é uma estratégia básica no domínio de entregas que é conhecido de qualquer empresário dessa indústria, mas normalmente nós, programadores, não sabemos disso. O requerimento que vem pra nós poderia ser algo como "Permitir 10% de overbooking", o diagrama de classes poderia ficar parecido com isto e o código seria atualizado da seguinte forma:
public int makeBooking(Cargo cargo, Voyage voyage) {
double maxBooking = voyage.capacity() * 1.1;
if ((voyage.bookedCargoSize() + cargo.size()) > maxBooking)
return -1;
int confirmation = orderConfirmationSequence.next();
voyage.addCargo(cargo, confirmation);
return confirmation;
}
Ou seja, no código determinamos quanto é o novo máximo com 10% a mais de overbooking e vemos se a mercadoria que queremos adicionar ultrapassa esse máximo. Mas isso cria um problema: agora temos uma regra de negócio escondida, como uma cláusula de guarda, no meio do método da aplicação.
Segundo o Eric, essa regra de overbooking é uma política. Política é outro nome pra um design pattern conhecido como Strategy. Em resumo, esse novo código poderia ser refatorado pra ter uma classe separada de OverbookingPolicy e no método de adicionar a mercadoria na viagem, chamar o método "isAllowed" dessa nova classes, e assim separar a política numa entidade separada, que documenta melhor essa regra em vez de deixar misturada e escondida com o código anterior.
public int makeBooking(Cargo cargo, Voyage voyage) {
if (!overbookingPolicy.isAllowed(cargo, voyage))
return -1;
int confirmation = orderConfirmationSequence.next();
voyage.addCargo(cargo, confirmation);
return confirmation;
}
class OverbookingPolicy {
public static double OVERBOOKING = 1.1;
public boolean isAllowed(Cargo cargo, Voyage voyage) {
double maxBooking = voyage.capacity() * OVERBOOKING;
return ((voyage.bookedCargoSize() + cargo.size()) <= maxBooking;
}
}
O vídeo do Akita em si é para não usar design patterns adoidamente, mas aqui o seu caso parece o contrário. O design pattern nesse caso tem a função de "expor" uma funcionalidade sem que ela fique hard-code no código. Até porque dá forma que você citou até dá para fazer rodar, só que fica mais díficil de realizar a manutenção dele
Os vídeos do Fabio Akita sobre modelagem de dados e do Deschamps sobre Factory e Injeção de Dependências ilustram bem isso: