Die meiste Zeit, wenn ich Code schreibe, der die Antwort für einen bestimmten Funktionsaufruf verarbeitet, erhalte ich die folgende Codestruktur:
Beispiel: Dies ist eine Funktion, die die Authentifizierung für ein Anmeldesystem übernimmt
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.
}
}
Problem
- Wie Sie sehen können, basiert der Code auf einer
if/else
Struktur, was bedeutet, dass ein neuer Fehlerstatus bedeutet, dass ich eineelse if
Anweisung hinzufügen muss , die einen Verstoß gegen das Open Closed-Prinzip darstellt . - Ich habe das Gefühl, dass die Funktion unterschiedliche Abstraktionsebenen aufweist, da ich möglicherweise nur den Zähler für Anmeldeversuche in einem Handler erhöhen, in einem anderen jedoch ernstere Aufgaben ausführen kann.
- Einige der Funktionen werden beispielsweise wiederholt
increase the login trials
.
Ich habe darüber nachgedacht, das Multiple if/else
in ein Factory-Muster zu konvertieren , aber ich habe Factory nur verwendet, um Objekte zu erstellen, ohne das Verhalten zu ändern. Hat jemand eine bessere Lösung dafür?
Hinweis:
Dies ist nur ein Beispiel für die Verwendung eines Anmeldesystems. Ich bitte um eine allgemeine Lösung für dieses Verhalten unter Verwendung eines gut aufgebauten OO-Musters. Diese Art von if/else
Handlern erscheint an zu vielen Stellen in meinem Code und ich habe das Anmeldesystem nur als einfaches, leicht zu erklärendes Beispiel verwendet. Meine wirklichen Anwendungsfälle sind zu kompliziert, um sie hier zu posten. : D.
Bitte beschränken Sie Ihre Antwort nicht auf PHP-Code und verwenden Sie die von Ihnen bevorzugte Sprache.
AKTUALISIEREN
Ein weiteres komplizierteres Codebeispiel, um meine Frage zu klären:
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();
}
}
Funktionszweck:
- Ich verkaufe Spiele bei ebay.
- Wenn ein Kunde seine Bestellung stornieren möchte und sein Geld zurückerhält (dh eine Rückerstattung), muss ich zuerst einen "Streit" bei ebay eröffnen.
- Sobald ein Streitfall eröffnet ist, muss ich warten, bis der Kunde bestätigt, dass er der Rückerstattung zustimmt (albern, da er mir gesagt hat, ich solle zurückerstatten, aber so funktioniert es bei ebay).
- Diese Funktion öffnet alle Streitigkeiten von mir und überprüft regelmäßig ihren Status, um festzustellen, ob der Kunde auf den Streit geantwortet hat oder nicht.
- Der Kunde kann zustimmen (dann erstatte ich) oder ablehnen (dann rolle ich zurück) oder 7 Tage lang nicht antworten (ich schließe den Streit selbst und erstatte dann).
getOrderStrategy
es sich um eine Factory-Methode handelt, die einstrategy
Objekt abhängig vom Auftragsstatus zurückgibt , aber was sind diepreProcess()
undpreProcess()
Funktionen. Auch warum übergeben Sie$this
anupdateOrderHistory($this)
?