Na maioria das vezes, quando estou escrevendo algum código que lida com a resposta para uma determinada chamada de função, recebo a seguinte estrutura de código:
exemplo: Esta é uma função que manipulará a autenticação para um sistema de login
class Authentication{
function login(){ //This function is called from my Controller
$result=$this->authenticate($username,$password);
if($result=='wrong password'){
//increase the login trials counter
//send mail to admin
//store visitor ip
}else if($result=='wrong username'){
//increase the login trials counter
//do other stuff
}else if($result=='login trials exceeded')
//do some stuff
}else if($result=='banned ip'){
//do some stuff
}else if...
function authenticate($username,$password){
//authenticate the user locally or remotely and return an error code in case a login in fails.
}
}
Problema
- Como você pode ver, o código é construído em uma
if/else
estrutura, o que significa que um novo status de falha significa que preciso adicionar umaelse if
declaração que seja uma violação do Princípio Aberto Fechado . - Sinto que a função tem diferentes camadas de abstração, pois posso apenas aumentar o contador de tentativas de login em um manipulador, mas fazer coisas mais sérias em outro.
- Algumas das funções são repetidas,
increase the login trials
por exemplo.
Pensei em converter o múltiplo if/else
em um padrão de fábrica, mas só usei o factory para criar objetos e não alterar comportamentos. Alguém tem uma solução melhor para isso?
Nota:
Este é apenas um exemplo usando um sistema de login. Estou pedindo uma solução geral para esse comportamento usando um padrão OO bem construído. Esse tipo de if/else
manipulador aparece em muitos lugares no meu código e eu apenas usei o sistema de login como um exemplo simples e fácil de explicar. Meus casos de uso reais são muito complicados para postar aqui. : D
Por favor, não limite sua resposta ao código PHP e sinta-se à vontade para usar a linguagem de sua preferência.
ATUALIZAR
Outro exemplo de código mais complicado apenas para esclarecer minha pergunta:
public function refundAcceptedDisputes() {
$this->getRequestedEbayOrdersFromDB(); //get all disputes requested on ebay
foreach ($this->orders as $order) { /* $order is a Doctrine Entity */
try {
if ($this->isDisputeAccepted($order)) { //returns true if dispute was accepted
$order->setStatus('accepted');
$order->refund(); //refunds the order on ebay and internally in my system
$this->insertRecordInOrderHistoryTable($order,'refunded');
} else if ($this->isDisputeCancelled($order)) { //returns true if dispute was cancelled
$order->setStatus('cancelled');
$this->insertRecordInOrderHistory($order,'cancelled');
$order->rollBackRefund(); //cancels the refund on ebay and internally in my system
} else if ($this->isDisputeOlderThan7Days($order)) { //returns true if 7 days elapsed since the dispute was opened
$order->closeDispute(); //closes the dispute on ebay
$this->insertRecordInOrderHistoryTable($order,'refunded');
$order->refund(); //refunds the order on ebay and internally in my system
}
} catch (Exception $e) {
$order->setStatus('failed');
$order->setErrorMessage($e->getMessage());
$this->addLog();//log error
}
$order->setUpdatedAt(time());
$order->save();
}
}
finalidade da função:
- Eu estou vendendo jogos no ebay.
- Se um cliente deseja cancelar seu pedido e receber seu dinheiro de volta (ou seja, um reembolso), primeiro devo abrir uma "disputa" no ebay.
- Depois que uma disputa é aberta, devo esperar que o cliente confirme que ele concorda com o reembolso (por mais tolo que ele tenha me dito para reembolsar, mas é assim que funciona no ebay).
- Essa função obtém todas as disputas abertas por mim e verifica seus status periodicamente para ver se o cliente respondeu ou não à disputa.
- O cliente pode concordar (depois reembolso) ou recusar (depois reverter) ou pode não responder por 7 dias (eu mesmo encerro a disputa e reembolso).
getOrderStrategy
é um método de fábrica que retorna umstrategy
objeto dependendo do status do pedido, mas quais são as funçõespreProcess()
epreProcess()
. Além disso, por que você passar$this
paraupdateOrderHistory($this)
?