Przez większość czasu, gdy piszę kod, który obsługuje odpowiedź na określone wywołanie funkcji, otrzymuję następującą strukturę kodu:
przykład: jest to funkcja, która będzie obsługiwać uwierzytelnianie w systemie logowania
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
- Jak widać, kod jest zbudowany na
if/elsestrukturze, co oznacza, że nowy stan awarii oznacza, że muszę dodaćelse ifoświadczenie, które narusza zasadę otwartej zamkniętej zasady . - Mam wrażenie, że funkcja ma różne warstwy abstrakcji, ponieważ mogę po prostu zwiększyć licznik prób logowania w jednym module obsługi, ale zrobić coś poważniejszego w innym.
- Niektóre funkcje są
increase the login trialsna przykład powtarzane .
Myślałem o przekształceniu wielokrotności if/elsena wzorzec fabryczny, ale użyłem fabryki tylko do tworzenia obiektów, a nie zmiany zachowań. Czy ktoś ma na to lepsze rozwiązanie?
Uwaga:
To tylko przykład z wykorzystaniem systemu logowania. Proszę o ogólne rozwiązanie tego zachowania przy użyciu dobrze zbudowanego wzorca OO. Tego rodzaju if/elseprogramy obsługi pojawiają się w zbyt wielu miejscach w moim kodzie i właśnie użyłem systemu logowania jako prostego, łatwego do wyjaśnienia przykładu. Moje prawdziwe przypadki użycia są zbyt skomplikowane, aby opublikować tutaj. :RE
Nie ograniczaj swojej odpowiedzi do kodu PHP i skorzystaj z preferowanego języka.
AKTUALIZACJA
Kolejny bardziej skomplikowany przykład kodu, aby wyjaśnić moje pytanie:
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();
}
}
cel funkcji:
- Sprzedaję gry w serwisie eBay.
- Jeśli klienci chcą anulować swoje zamówienie i odzyskać pieniądze (tj. Zwrot pieniędzy), najpierw muszę otworzyć „spór” w serwisie eBay.
- Gdy spór zostanie otwarty, muszę poczekać, aż klient potwierdzi, że zgadza się na zwrot pieniędzy (głupie, ponieważ to on kazał mi zwrócić pieniądze, ale tak to działa w serwisie eBay).
- Ta funkcja otwiera wszystkie spory przeze mnie i okresowo sprawdza ich status, aby sprawdzić, czy klient odpowiedział na spór, czy nie.
- Klient może wyrazić zgodę (następnie zwracam pieniądze) lub odmówić (następnie wycofuję) lub może nie odpowiadać przez 7 dni (sam zamykam spór, a następnie zwracam pieniądze).
getOrderStrategyjest to metoda fabryczna, która zwracastrategyobiekt w zależności od statusu zamówienia, ale jakie są funkcjepreProcess()ipreProcess(). Również dlaczego przejść$thisdoupdateOrderHistory($this)?