Більшу частину часу, коли я пишу якийсь код, який обробляє відповідь на певний виклик функції, я отримую таку структуру коду:
Приклад: Це функція, яка буде обробляти аутентифікацію для системи входу
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.
}
}
Проблема
- Як ви бачите, що код побудований на
if/else
структурі, що означає, що новий статус відмови означатиме, що мені потрібно додатиelse if
заяву, що є порушенням для відкритого закритого принципу . - У мене виникає відчуття, що функція має різні шари абстракції, тому що я можу просто збільшити лічильник випробувань входу в одному обробнику, але робити більш серйозні речі в іншому.
- Деякі функції повторюються,
increase the login trials
наприклад.
Я думав про перетворення множини if/else
на заводський зразок, але я використовував лише фабрику для створення об'єктів, що не змінюють поведінку. Хтось має для цього краще рішення?
Примітка:
Це лише приклад використання системи входу. Я прошу загального рішення такої поведінки, використовуючи добре побудовану схему ОО. Цей вид if/else
обробників з'являється в занадто багато місць у моєму коді, і я просто використовував систему входу як простий простий для пояснення приклад. Мої реальні випадки використання - це набагато складніше розміщувати тут. : D
Будь ласка, не обмежуйте свою відповідь кодом PHP і не соромтесь використовувати мову, яку ви бажаєте.
ОНОВЛЕННЯ
Ще один складніший приклад коду просто для уточнення мого питання:
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();
}
}
призначення функції:
- Я продаю ігри на ebay.
- Якщо клієнт бажає скасувати його замовлення і отримає його гроші назад (тобто повернення коштів), я повинен спершу відкрити "Диспут" на ebay.
- Як тільки суперечка буде відкрита, я повинен зачекати, коли клієнт підтвердить, що він погоджується на повернення коштів (нерозумно, оскільки він сказав мені повернути гроші, але це працює як на ebay).
- Ця функція отримує всі відкриті мною суперечки і періодично перевіряє їхні статуси, щоб побачити, відповів клієнт на суперечку чи ні.
- Клієнт може погодитись (тоді я відшкодую) або відмовитись (тоді я відкату) або не відповісти протягом 7 днів (я закриваю суперечку, потім відшкодую).
getOrderStrategy
це заводський метод, який повертаєstrategy
об'єкт залежно від стану замовлення, але які єpreProcess()
таpreProcess()
функції. Крім того, чому ви передаєте$this
вupdateOrderHistory($this)
?