La plupart du temps, lorsque j'écris du code qui gère la réponse pour un certain appel de fonction, j'obtiens la structure de code suivante:
exemple: il s'agit d'une fonction qui gérera l'authentification pour un système de connexion
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.
}
}
Problème
- Comme vous pouvez le voir, le code est construit sur une
if/else
structure, ce qui signifie qu'un nouveau statut d'échec signifie que je dois ajouter uneelse if
instruction qui constitue une violation du principe ouvert et fermé . - J'ai l'impression que la fonction a différentes couches d'abstraction car je peux simplement augmenter le compteur d'essais de connexion dans un gestionnaire, mais faire des choses plus sérieuses dans un autre.
- Certaines fonctions sont répétées
increase the login trials
par exemple.
J'ai pensé à convertir le multiple if/else
en un motif d'usine, mais je n'ai utilisé l'usine que pour créer des objets et non pour modifier les comportements. Quelqu'un at-il une meilleure solution pour cela?
Remarque:
Ceci est juste un exemple d'utilisation d'un système de connexion. Je demande une solution générale à ce comportement en utilisant un modèle OO bien construit. Ce type de if/else
gestionnaires apparaît à trop d'endroits dans mon code et je viens d'utiliser le système de connexion comme exemple simple et facile à expliquer. Mes cas d'utilisation réels sont trop compliqués à publier ici. :RÉ
Veuillez ne pas limiter votre réponse au code PHP et n'hésitez pas à utiliser la langue que vous préférez.
MISE À JOUR
Un autre exemple de code plus compliqué juste pour clarifier ma question:
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();
}
}
but de la fonction:
- Je vends des jeux sur ebay.
- Si un client souhaite annuler sa commande et récupérer son argent (c'est-à-dire un remboursement), je dois d'abord ouvrir un "Litige" sur ebay.
- Une fois qu'un litige est ouvert, je dois attendre que le client confirme qu'il accepte le remboursement (idiot car c'est lui qui m'a dit de rembourser, mais c'est comme ça que ça fonctionne sur ebay).
- Cette fonction obtient tous les litiges ouverts par moi et vérifie périodiquement leur statut pour voir si le client a répondu au litige ou non.
- Le client peut accepter (puis je rembourse) ou refuser (puis je recule) ou peut ne pas répondre pendant 7 jours (je clore le litige moi-même puis rembourser).
getOrderStrategy
s'agit d'une méthode d'usine qui renvoie unstrategy
objet en fonction du statut de la commande, mais quelles sont les fonctionspreProcess()
etpreProcess()
. Et pourquoi es-tu passé$this
àupdateOrderHistory($this)
?