La maggior parte delle volte in cui 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 è basato su una struttura
if/else
il che significa che un nuovo stato di errore significherà che devo aggiungere un'istruzioneelse if
che è una violazione per il Open Closed Principle . - 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
ad esempio.
Ho pensato di convertire il multiplo if/else
in uno schema di fabbrica, ma ho usato solo la fabbrica per creare oggetti che non alteravano i comportamenti. Qualcuno ha una soluzione migliore per questo?
Nota:
Questo è solo un esempio utilizzando un sistema di accesso. Sto chiedendo una soluzione generale a questo comportamento usando un modello OO ben costruito. Questo tipo di if/else
handler appare in troppi punti nel mio codice e ho appena usato il sistema di login come un semplice esempio di facile spiegazione. I miei casi d'uso reali sono molto più complicati da pubblicare qui. : D
Non limitare la tua risposta al codice PHP e sentiti libero di usare la lingua che preferisci.
Aggiorna
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:
- Sto vendendo giochi su ebay.
- Se un cliente desidera annullare il suo ordine e ottiene indietro i suoi soldi (Ad esempio un rimborso) Devo prima aprire una "contestazione" su ebay.
- Una volta aperta una controversia, devo aspettare che il cliente confermi ciò accetta il rimborso (sciocco perché è lui che mi ha detto di rimborsare, ma è così che funziona su ebay).
- Questa funzione ottiene tutte le controversie aperte da me e controlla periodicamente i loro stati per vedere se il cliente ha risposto o meno alla controversia.
- Il cliente può concordare (quindi rimborsare) o rifiutare (quindi eseguo il rollback) o non rispondere per 7 giorni (chiudo la contestazione quindi rimborserò).