Il più delle volte quando scrivo del codice che gestisce la risposta per una determinata chiamata di funzione ottengo la seguente struttura di codice:
esempio: questa è una funzione che gestirà l'autenticazione per un sistema di 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
- Come puoi vedere, il codice si basa su una
if/else
struttura, il che significa che un nuovo stato di errore significherà che devo aggiungereelse if
un'istruzione che costituisce una violazione del principio chiuso aperto . - Ho la sensazione che la funzione abbia diversi livelli di astrazione in quanto potrei semplicemente aumentare il contatore delle prove di accesso in un gestore, ma fare cose più serie in un altro.
- Alcune funzioni sono ripetute
increase the login trials
per esempio.
Ho pensato di convertire il multiplo if/else
in un modello factory, ma ho usato solo factory per creare oggetti senza alterare i comportamenti. Qualcuno ha una soluzione migliore per questo?
Nota:
Questo è solo un esempio usando un sistema di login. Sto chiedendo una soluzione generale a questo comportamento usando un modello OO ben costruito. Questo tipo di if/else
gestori appare in troppi punti del mio codice e ho appena usato il sistema di login come un semplice esempio facile da spiegare. I miei casi d'uso reali sono molto complicati da pubblicare qui. : D
Non limitare la tua risposta al codice PHP e sentiti libero di usare la lingua che preferisci.
AGGIORNARE
Un altro esempio di codice più complicato solo per chiarire la mia domanda:
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();
}
}
scopo della funzione:
- Vendo giochi su ebay.
- Se un cliente desidera annullare il suo ordine e ottenere indietro i suoi soldi (ad esempio un rimborso), devo prima aprire una "Controversia" su ebay.
- Una volta aperta una controversia, devo attendere che il cliente confermi che accetta il rimborso (sciocco perché è lui che mi ha detto di rimborsare, ma è così che funziona su eBay).
- Questa funzione mi consente di aprire tutte le controversie e di controllare periodicamente il loro stato per vedere se il cliente ha risposto alla controversia o meno.
- Il cliente può concordare (quindi rimborsare) o rifiutare (quindi eseguire il rollback) o non rispondere per 7 giorni (chiudo la controversia e quindi rimborso).
getOrderStrategy
è un metodo di fabbrica che restituisce unstrategy
oggetto in base allo stato dell'ordine, ma quali sono le funzionipreProcess()
epreProcess()
. Anche perché sei passato$this
aupdateOrderHistory($this)
?