Meilleur modèle de conception POO pour une séquence d'opérations


11

Je travaille sur une application dont un module effectue successivement les opérations financières suivantes:

Lorsqu'un utilisateur demande qu'un certain montant soit transféré sur son compte bancaire:

  1. vérifier si une transaction peut avoir lieu maintenant? (la transaction ne peut être effectuée que pendant une certaine période)
  2. vérifier si l'utilisateur a demandé le retrait d'un montant minimum
  3. vérifier si l'utilisateur a un compte par défaut

Le résultat de toutes les actions ci-dessus doit être enregistré.

Si toutes les conditions ci-dessus sont remplies, la transaction est effectuée. À l'avenir, il pourrait y avoir des vérifications supplémentaires.

Quel modèle de conception orienté objet devrait être le mieux adapté au cas ci-dessus?


3
Ne cherchez jamais un modèle de conception pour résoudre un problème. Utilisez des modèles de conception pour communiquer la bonne solution. programmers.stackexchange.com/questions/70877/… Suivez les principes SOLID et vous ne vous tromperez pas.
pdr

2
Je ne suis pas d'accord. Les modèles ont des noms qui facilitent la communication et ils doivent également être utilisés pour communiquer des solutions. Mais je ne suis pas d'accord avec "Ne jamais chercher un modèle de conception pour résoudre un problème". Ils ne résolvent pas seulement des problèmes spécifiques, mais ils traitent également de différentes forces et contraintes. Jetez un œil à "Proxy" et "Decorator". Ils se ressemblent mais résolvent des problèmes différents. Donc, à mon avis, avant de résoudre un problème vous-même, vous devriez au moins jeter un coup d'œil à des modèles de conception bien connus afin de profiter des deux, une approche standard pour résoudre un problème et un moyen facile de le communiquer.
Jonny Dee

10
Voici une bonne caractérisation de ce qu'est un modèle: «Ils [les modèles] fournissent des solutions fonctionnelles, concrètes et adaptables aux problèmes qui surviennent à plusieurs reprises dans certaines situations au cours du développement de logiciels, de l'organisation à la programmation.» [POSA5, p. 30] Donc, de ce point de vue, il est tout à fait clair que la recherche d'un modèle comme solution adaptable est une approche ligitimée.
Jonny Dee

3
Demandez-vous une construction orientée objet afin de décrire une ancienne programmation procédurale simple?
mouviciel

4
Suivez le principe KISS. Jusqu'à présent, votre problème peut être résolu avec 3 instructions "if" dans une seule méthode. N'essayez pas d'utiliser un motif de conception juste pour être cool. Chaque fois que vous écrivez un cours supplémentaire, pensez toujours: en ai-je vraiment besoin?
Eiver

Réponses:


13

Cela ressemble à ce que vous recherchez est une chaîne de responsabilité . Dans ce cas, vous pourriez avoir les classes suivantes:

  • TransactionValidatorBase classe de base abstraite
  • TransactionTimeValidator
  • TransactionAmountValidator
  • TransactionAccountValidator

Ceux-ci sont enchaînés pour appliquer le nombre de règles que vous spécifiez.

Furter Reading


11
Ma compréhension est que la chaîne de responsabilité est plus un filtre - c'est-à-dire que nous descendons la chaîne jusqu'à ce que nous trouvions quelqu'un équipé pour faire face à la responsabilité, alors ce "maillon" gérera la responsabilité et quittera. Un défaut du COR en termes pratiques est qu'il est difficile de lui faire retourner une valeur, dont il semble que vous pourriez avoir besoin pour cela.
Amy Blankenship

Je pense que vous pouvez avoir une chaîne de R. à un niveau. Je ne pense pas vraiment qu'il soit difficile de renvoyer une valeur à partir d'une chaîne, avec un peu d'abtraction. Chaque niveau sera nécessaire pour communiquer en adhérant à une certaine interface primitive, et devra accepter une entrée par le bas, étant donné que cette entrée est conforme à l'interface primitive. Lorsque la richesse d' interface est nécessaire entre deux niveaux de chaîne qui sont plus intimement couplés, l'abtraction peut être poly-morphée pour le supporter.
Andyz Smith

2

Le modèle correct ici dépend vraiment d'un contexte. Avant de choisir un modèle particulier à respecter, je vais essayer de trouver des réponses à ces questions:

  • Est-il nécessaire de créer différentes combinaisons de (1,2,3) contrôles au moment de l'exécution?
  • Ont-ils besoin des mêmes variables pour effectuer leurs actions ou sont-ils très différents?
  • Quelle doit être la précision des messages d'erreur?
  • En cas d'échec, l'utilisateur essaie-t-il toujours de (1) première étape?
  • Comment la concurrence est-elle gérée?
  • Chaque méthode ajoute-t-elle quelque chose à la demande ou valide-t-elle simplement? (dites l'identifiant de compte par défaut?)

Basé sur une intuition, je les coderais comme des méthodes simples avec un paramètre d'agrégation pour les codes d'erreur.

public void DoTransaction(IErrorAgregator error, TransactionRequest request)
{
    if(!IsTransactionInCertainTimePeriod(request, error)) return;
    if(!IsTransactionAmountInUserBounds(request, error)) return;
    if(!UserHaveDefaultAccount(request, error)) return;
    bankingTransactor.PerformTransaction(request);
}

Ce pourrait être une bonne idée de mettre DoTransaction dans l'interface "ITransactionValidationStragegy" et de créer un super-type de couche qui contiendra le code passe-partout de validation.

Cependant, dans cette conception, je suppose que la logique de validation est déterminée au moment de la compilation.


2

Si votre séquence d'étapes fait principalement des tâches de validation (comme il vous semble), sans muter les entrées, je penserais en effet au modèle de "chaîne de responsabilité", comme expliqué dans sa réponse par @pswg

Mais comme votre question est un peu plus générique, j'aimerais également ajouter le "traitement Pipeline", car avec celui-ci, une étape produirait une sortie qui deviendrait l'entrée pour l'étape suivante (mutant ainsi l'entrée d'origine) .

Voici deux articles à ce sujet:
Collection Pipeline par Martin Fowler
Plus de discussion théorique sur le modèle


0

Bien que les modèles soient déjà mentionnés ici, je vous suggère de réfléchir à la façon dont vous souhaitez les utiliser dans votre application, en fonction des cadres que vous utilisez.

Par exemple, la validation que vous aimeriez faire, très probablement, continuera de changer au fur et à mesure que le temps avance (vous souhaiterez peut-être ajouter une nouvelle validation à l'avenir qui limite les transactions à 10 par jour). En outre, vous ne souhaiterez peut-être pas effectuer la validation avant que votre service commercial ou votre code d'intégration ne se déclenche. Ce serait bien, si vous pouviez ajouter les validations en tant que validations configurables.

Dans le cas où vous utilisez Struts, l'utilisation d'intercepteurs peut être une bonne idée. En cas de printemps, l'injection de haricots comme dépendance vous donne plus de souplesse. Ma suggestion est non seulement de regarder les modèles / idiomes, mais aussi de regarder le cadre que vous utilisez pour construire l'application et de voir comment vous pouvez mieux répondre à vos besoins d'un point de vue futuriste.


-2

Selon ma compréhension, tout ce qui est requis peut être intégré dans le modèle de commande comme ci-dessous. La conception de la classe peut être effectuée comme ci-dessous.

interface Transaction{
void performAction();
}

class Banking{

void moneyValidation(){
//Validate Here
}

void timeValidation(){
//validate Here
}
}

class TimeValidation implements Transaction{

public Banking bank;

public TimeValidation (Banking bnk){
bank=bnk;
}

void performAction(){
bnk.timeValidation();
}


class MoneyValidation Implements Transaction{

public Banking bank;

public MoneyValidation(Banking bnk;){
bank=bnk;
}

void performAction(){
bnk.moneyValidation();
}
}


class Control{

private List val_list=new ArrayList();

void storeValidation(Transaction trans){
val_list.add(trans);
trans.performAction(val_list.getFirstAndRemove());
}
}

//Same for other validation classes

Votre classe Client contiendra l'extrait de code suivant:

Banking bnk = new Banking();
MoneyValidation m_val = new MoneyValidation (bnk);
TimeValidation t_val = new TimeValidation (bnk);
Control ctrl = new Control();
ctrl.storeValidation(m_val);
ctrl.storeValidation(t_val);

C'est selon ma compréhension, avec le scénario qui a été donné ci-dessus.


C'est mauvais parce que lorsque la validation de l'argent échoue, la validation du temps est inutile mais elle sera quand même effectuée
Ewoks
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.