Existe-t-il un modèle de conception qui s'appliquerait aux modèles à escompte?

35

Existe-t-il des modèles de conception connus pour la mise en œuvre de modèles à escompte?

Par modèles à prix réduits, j'entends ce qui suit:

  1. Si un client achète le produit X, le produit Y et le produit Z, il bénéficie d'une réduction de 10% ou de 100 $.

  2. Si un client achète 100 unités du produit X, il obtient un rabais de 15% ou 500 $

  3. Si un client a rapporté l'année dernière plus de 100 000 dollars, il bénéficie d'une réduction forfaitaire de 20%.

  4. Si un client a acheté 2 unités du produit X, il obtient gratuitement 1 unité du produit X (ou du produit Y).

  5. ...

Existe-t-il un modèle générique pouvant être appliqué pour gérer tous les scénarios ci-dessus? Je pense à quelques modèles, mais je suis incapable de trouver un modèle générique.

Kanini
la source
IIRC tous les tutoriels que j'ai vu avec des exemples impliquant des réductions (il y a beaucoup) suggèrent modèle Stratégie
moucheron
2
@ Kanini Est-ce un problème du monde réel? Dans un tel cas, ce système est-il en temps réel ou différé? Ces règles sont-elles présentées comme des valeurs de moteur de règles ou de base de données? La recherche de remises est-elle hiérarchisée par priorité? Le modèle de stratégie fonctionnerait dans la plupart des cas, mais vos règles doivent être décomposées pour le faire fonctionner
Ubermensch
3
De plus, si quelqu'un achète 2 unités de produit X, un produit Y et un produit Z, obtiendrait-il à la fois 10% et un produit X supplémentaire?
Ubermensch
@gnat quelques liens vers certains de ces tutoriels s'il vous plaît.
user16764

Réponses:

18

Si le problème est que vous devez appliquer plusieurs remises, dans certaines circonstances, vous pouvez envisager le modèle de chaîne de responsabilité .

En un mot, vous transmettez les informations que vous souhaitez traiter au premier processeur, qui décide ensuite s'il convient de les transmettre à d'autres processeurs avant de renvoyer le résultat.

De cette façon, vous pouvez changer la structure et la séquence des processeurs sans jamais changer le code d'appel.

pdr
la source
Chaîne de responsabilité est un autre bon. Peut-être même être associé à une stratégie. Dans le cas où un seul rabais peut être appliqué, chaque stratégie est enchaînée à une autre. Chaque chaîne calcule sa remise (si le client est éligible), la compare à la remise précédente et transmet les données du client, de la commande et de la remise à la chaîne suivante. +1
Thomas Owens
1
Juste mon opinion, mais je trouve plus probable que "Chaîne de responsabilité" sur-conçoit pour ce cas. Une simple liste de modèles de remises (si nécessaire, avec un numéro de commande) devrait le faire. La liste elle-même est indépendante du client et de ses commandes, car tous les clients doivent être traités de manière égale. La "chaîne de responsabilité" est plus appropriée lorsque la liste des modèles de remises change très fréquemment au moment de l'exécution de manière très dynamique.
Doc Brown
11

Les modèles de stratégie, de décorateur et d'état me paraissent constituer des points de départ potentiels. State peut être particulièrement utile pour 2 ou 3, car 2 dépend de l'état de la commande et 3 dépend de l'état du client au cours d'une période donnée. Stratégie et Décorateur se distinguent des autres, car vous pouvez utiliser stratégie pour implémenter plusieurs algorithmes de calcul du prix de la commande et décorateur pour ajouter de nouvelles remises à la commande.

Cependant, rappelez-vous que les modèles de conception ne sont que des modèles. Il se peut qu’il n’y ait pas un seul modèle qui s’applique, mais plutôt un système de modèles. Pensez également à apporter des modifications aux modèles décrits pour les adapter davantage à votre solution. Il est préférable d’avoir un bon design que de forcer un motif qui n’aide pas forcément pour pouvoir dire que vous avez un motif.

Thomas Owens
la source
Ce n'est pas vraiment ce que le modèle d'état est censé faire, n'est-ce pas?
pdr le
@pdr Je ne vois pas pourquoi pas. Mais cela dépend de votre implémentation. Si votre objet client suit les remises dépendantes du client, une opération de restitution des remises auxquelles le client est admissible peut alors avoir lieu. Au fur et à mesure que le client achète des objets, les attributs changent et l'implémentation de cette méthode change via le modèle d'état.
Thomas Owens
1
Hmm, je vois ce que vous voulez dire. Je pense que cela dépend si le client est un objet semi-permanent dans l'application ou tout simplement quelque chose qui réside dans la base de données et doit être mis à jour. Ce n'est pas clair d'après la question, alors assez juste. +1
pdr le
3
D'après mon expérience, ce type de règles commerciales d'actualisation est constamment modifié par les départements marketing / ventes instables. Il est impératif de les rendre pilotés par les données et modifiables par l'utilisateur plutôt que par le code. Comment cela affecterait-il le choix du modèle?
Jfrankcarr le
@ jfrankcarr Dans mon esprit, ce ne serait pas le cas. J'indiquerais les valeurs pour des ensembles d'éléments entraînant une remise, les pourcentages de réduction, etc. à partir d'une configuration quelconque. Construire de manière dynamique mes transitions de machine à états et les attributs de mes décorateurs et stratégies.
Thomas Owens
10

Eh bien, je concevrais un modèle d’escompte comme une paire "Précondition" et "Escompte", où "Précondition" est une classe avec méthodes.

  bool IsFulfilled(Customer c);

ou et

  bool IsFulfilled(Customer c, Order o);

et Discount a une méthode void ApplyTo(Customer c). Cela vous donne la possibilité de combiner n'importe quel type de condition préalable avec n'importe quel type de réduction (je pense qu'il s'agit d'une forme de "modèle de pont").

Si vous avez un nombre fixe de conditions préalables, vous pouvez résoudre le problème en créant des sous-types spécifiques (modèle de stratégie). Toutefois, lorsque vos conditions préalables sont considérées comme très complexes, avec des instructions logiques telles que AND, OR et NOT, vous pouvez mieux implémenter un interpréteur de règles pour les conditions. Les règles peuvent être une chaîne de texte en clair écrite dans un "langage spécifique à un domaine".

Il en va de même pour la classe "Remise", vous pouvez avoir soit des sous-types pour différents types de remises, soit une approche générale dans laquelle les règles de remise sont données sous forme de texte, évaluée par un interprète.

Doc Brown
la source
Mon intuition suggère que cela pourrait être ce qu'il recherche dans le contexte de la question
Ubermensch
4
  • Il faut probablement une interface IDiscount, car toutes les remises sont identiques, et nous voudrons les traiter de manière conceptuelle en tant que remises génériques.

  • La classe "commande de ce client" nécessite probablement une collection de remises. Liste? Hacher? Liste liée? Ne t'en fous pas encore. Des rabais s'appliquent à l'achat, pas au client!

  • Conservez le bâtiment de l'instance Discount à l'écart du client, du panier d'achat, de l'historique, etc. Cela changera beaucoup - comme l'a souligné @jfrankcarr.

  • Probablement une classe différente pour chaque remise car l'algorithme et les paramètres de chaque remise varient énormément et de façon imprévisible.

  • Je considère que la gestion des événements est très fréquente, car le calcul des remises répond aux modifications du panier, et inversement.

Application de modèle de conception

  • Je vois un strategy pattern. IDiscount est l'interface permettant d'implémenter différents algorithmes de réduction.
  • Je vois un factory. Certainement pas une abstract factory patternclasse à part entière , mais une seule classe à ce stade de l'analyse. Raisonnablement, il doit exister un seul endroit où le contexte est suffisant pour décider des remises applicables et les créer ensuite. Une classe. Si les règles relatives à l'application de remises explosent par la suite en raison d'une fête organisée par le département du marketing, toute logique supplémentaire de construction de remises doit quand même fusionner dans cette classe d'usine de base, à mon avis.

  • Je peux voir Chain of Responsibility. Ce n'est pas mutuellement exclusif à l' factoryidée. Au lieu d'itérer une collection de remises, chaque remise appelle le type suivant. La classe "commande du client" ne contient pas une collection de remises dans ce cas.

  • Le facteur "hmmmm ...." dans la chaîne de responsabilité, je pense, est que chaque remise a une référence à la suivante. L'implication est que l'ordre est important. Ce qui n'est pas le cas. En outre, le concept incarné par le CdR est qu'un objet ne peut pas gérer la demande , elle est donc transmise "à l'autorité suivante." Notre modèle est différent. La seule demande est de calculer. Chaque réduction fait ceci. La sortie ou l'effet peuvent être nuls, mais chaque remise est calculée. Je me penche instinctivement vers une plus grande fidélité dans le monde réel.

Hypothèses

  • Les remises sont basées sur le panier d'achat actuel et / ou l'historique des achats
  • Zéro ou plusieurs rabais peuvent s'appliquer. Il n'y a pas de rabais mutuellement exclusif
  • Un calcul correct ne dépend pas de l'ordre dans lequel les remises sont appliquées.

Qu'est-ce qui change, qu'est-ce qui reste pareil?

  • Les remises sont très différentes. Nombre et type de paramètres différents pour chaque règle.

  • Les arguments en faveur des remises admissibles changent en fonction des modifications du panier.

  • Le nombre de remises disponibles change

  • Les remises accordées par ce client aux modifications apportées en fonction de l'évolution de son panier.

  • L'historique des achats ne change pas dans le contexte de cet achat

  • Le coût total change de manière dynamique en fonction des lignes d'achat et des remises appliquées.

  • Après l'application initiale, le résultat de la remise peut changer, par exemple lorsque la quantité achetée change.

radarbob
la source
Excellente et complète réponse ... MAIS je n’ai qu’une préoccupation et c’est que la section des hypothèses ne devrait pas être là, du moins ne pas diriger la réponse. L'idée est que le modèle aide à rassurer et à oublier les "hypothèses", la règle générique n'a pas besoin de savoir comment les calculs sont effectués ni ce que toute implémentation détaillée utilise dans le contexte (Client, Articles du panier , Jour, saison, etc.). Vraiment aider plein si
le0diaz
La partie initiale sur les balles et la section "Hypothèses" ne sont que mon raisonnement "montrer votre travail" sur le problème lui-même qui, bien sûr, a un intérêt pour le modèle de modèle à escompte. Par exemple, mes hypothèses sur l'ordre d'exécution des réductions et l'interdépendance m'ont amené à minimiser l'importance de la chaîne de responsabilité. Notez que je pense à l'intention du motif, pas à la complexité comme le fait @docbrown. Je suis un partisan exubérant de refléter l'intention dans la conception.
radarbob
1

Logiquement, un modèle de réduction peut être n'importe quoi , vous ne pouvez donc pas supposer que vous pouvez programmer tous les cas à l'avance. Quiconque répond à votre question ne peut pas non plus être complètement sûr de ce dont vous avez réellement besoin. Cependant, en supposant que vous obteniez les types de rabais habituels trouvés dans le monde réel ...

Une grande question est de savoir si les réductions seront programmées ou si vous voulez que les utilisateurs les saisissent. Comme mentionné ci-dessus, vous ne pouvez jamais les programmer, mais l'objectif consiste généralement à essayer de créer davantage de données, comme dans les cas courants, plutôt que de les programmer toutes. Ceci s’applique dans une certaine mesure même si les programmeurs sont utilisés pour créer toutes les remises.

Martin Fowler mentionne "Méthode d'instance individuelle" dans "Modèles d'analyse: modèles d'objet réutilisables" dans le cadre de la mise en œuvre de "Règles de comptabilisation" pour les systèmes de comptabilité, mais les règles semblent assez similaires aux vôtres. Je donnerais plus de détails, mais c'est une œuvre protégée par le droit d'auteur et

Pour une interface utilisateur, vous devez soit proposer des cas d’utilisation assez simples, soit créer un interpréteur et un générateur de requêtes. Peut-être les deux, un pour les cas simples et un plus avancé. Si vous écrivez un interprète, c'est probablement un assez bon cas pour utiliser le motif Interpreter, puisqu'il est relativement simple à coder par rapport à un générateur d'analyseur, et que le temps d'analyse plus lent n'aura probablement pas d'importance. (Si vous aimez utiliser des générateurs d'analyseur, ne me laissez pas vous arrêter).

Cependant, n'essayez pas de tout faire avec un interprète - à un moment donné, vous programmez simplement dans votre propre langage minable, vous pouvez donc aussi bien utiliser un vrai langage. Si votre langage interprété prend en charge des fonctions (il devrait probablement prendre en charge leur appel - leur définition est douteuse), celles-ci peuvent être codées dans un langage réel. N'allez pas plus loin dans cette voie que nécessaire.

Peu importe ce que vous faites, quelqu'un voudra éventuellement que le rabais soit calculé en fonction de son achat dans les 30 jours ouvrables suivant une promotion - les jours ouvrables étant pris en compte uniquement s'il n'y a pas eu de jour férié dans la région définie par le code postal du magasin ou par le client. code postal. N'essayez donc pas de concevoir le système parfait à l'avance. Supposons que vous deviez parfois écrire du code pour de nouveaux types de remises et concevoir en conséquence.

psr
la source
0

Est-il utile de demander s'il existe un modèle utile pour cela? Quel type de modèle est requis - structurel ou comportemental?

Idéalement, si je devais écrire un logiciel pour cela, tout ce qu'il faudra, c'est un algorithme . Une fonction simple qui calcule la remise totale comme suit:

cart.calculateDiscount(productVector);

Vous n'avez pas besoin de plus que ça!

Pour clarifier: je comprends qu’il y aura de nombreuses règles - la représentation la plus élémentaire devrait être sous la forme d’une base de règles (ensemble d’attributs de données et de la réduction résultante contre celle-ci) et la fonction telle que celle décrite ci-dessus l’itérerait pour la calculer. Si des règles sont ajoutées ou supprimées, vous ne devriez pas changer le code; changez simplement la base de règles.

Un modèle n'est requis que si nous avons besoin de différents objets pour pouvoir accéder aux API les uns des autres ou communiquer pour mettre une tâche en place.

PS: Pensez-y: lorsque le pare-feu traite les paquets et les transmet ou les rejette (ou le modifie), quel modèle de conception utilise-t-il? La réponse est AUCUNE de celles décrites ci-dessus!

Dipan Mehta
la source
Bien sûr, vous avez besoin de plus que ça !!! L'idée est que l'algorithme n'est pas étroitement lié à la mise en œuvre du code. Si vous vérifiez les scénarios, il est fort probable que d'autres scénarios se présentent, vous l'avez également mentionné d'une manière ou d'une autre, il ne sait pas vraiment ce que toute autre «règle» dépendra. Il est naïf de penser qu’une règle ne dépend que de la liste de produits, mais dépend en réalité du client, du temps, de la saison, etc. Je ne sais pas quelle implémentation de pare-feu vous avez vérifiée, mais celles que j'ai
vérifiées DOIVENT avoir de