Je dois implémenter certaines règles métier avec des centaines de lignes de code ci-dessous
if this
then this
else if
then this
.
. // hundreds of lines of rules
else
that
Avons-nous un modèle de conception capable de l'implémenter efficacement ou de réutiliser le code afin qu'il puisse être appliqué à toutes les règles différentes. J'ai entendu parler du modèle de spécification qui crée quelque chose comme ci-dessous
public interface Specification {
boolean isSatisfiedBy(Object o);
Specification and(Specification specification);
Specification or(Specification specification);
Specification not(Specification specification);
}
public abstract class AbstractSpecification implements Specification {
public abstract boolean isSatisfiedBy(Object o);
public Specification and(final Specification specification) {
return new AndSpecification(this, specification);
}
public Specification or(final Specification specification) {
return new OrSpecification(this, specification);
}
public Specification not(final Specification specification) {
return new NotSpecification(specification);
}
}
Et puis l'implémentation des méthodes Is, And, Or mais je pense que cela ne peut pas m'empêcher d'écrire le if else (peut-être que ma compréhension est incorrecte) ...
Existe-t-il une meilleure approche pour mettre en œuvre de telles règles métier ayant autant d'instructions if else?
EDIT: Juste un exemple d'exemple.A, B, C, etc. sont les propriétés d'une classe.En dehors de cela, il y a beaucoup d'autres règles.Je veux faire un code générique pour cela.
If <A> = 'something' and <B> = ‘something’ then
If <C> = ‘02’ and <D> <> ‘02’ and < E> <> ‘02’ then
'something'
Else if <H> <> ‘02’ and <I> = ‘02’ and <J> <> ‘02’ then
'something'
Else if <H> <> ‘02’ and <I> <> ‘02’ and <J> = ‘02’ then
'something'
Else if <H> <> ‘02’ and <I> = ‘02’ and <J> = ‘02’ then
'something'
Else if <H> = ‘02’ and <I> = ‘02’ and <J> <> ‘02’ then
'something'
Else if <H> = ‘02’ and <I> <> ‘02’ and <J> = ‘02’ then
'something'
Else if <H> = ‘02’ and <I> = ‘02’ and <J> = ‘02’ then:
If <Q> = Y then
'something'
Else then
'something'
Else :
Value of <Z>
Le modèle de stratégie pourrait être utile ici. Veuillez vérifier Remplacer la logique conditionnelle par la stratégie
Vous pouvez utiliser Modèle de commande ou Modèle d'usine .
Le modèle de commande peut être utilisé pour remplacer les blocs commutateur/if encombrants qui ont tendance à croître indéfiniment lorsque vous ajoutez de nouvelles options.
public interface Command {
void exec();
}
public class CommandA() implements Command {
void exec() {
// ...
}
}
// etc etc
puis construisez un Map<String,Command>
objet et remplissez-le avec des instances de commande:
commandMap.put("A", new CommandA());
commandMap.put("B", new CommandB());
alors vous pouvez remplacer votre chaîne if/else if par:
commandMap.get(value).exec();
Dans Pattern Factory vous incluez votre if/switch dans une Factory qui prend soin de la laideur et cache l'abondance des ifs. Exemple de code pour le modèle d'usine .
Vous devriez vérifier le modèle de conception des règles http://www.michael-whelan.net/rules-design-pattern/ . Il ressemble beaucoup à l'exemple de code que vous avez donné et se compose d'une interface de base qui définit une méthode pour déterminer si une règle est satisfaite, puis diverses implémentations concrètes pour différentes règles. Si je comprends bien, votre instruction switch se transformerait en une sorte de boucle simple qui évalue simplement les choses jusqu'à ce que votre composition de règles soit satisfaite ou échoue.
interface IRule {
bool isSatisfied(SomeThing thing);
}
class RuleA: IRule {
public bool isSatisfied(SomeThing thing) {
...
}
}
class RuleB: IRule {
...
}
class RuleC: IRule {
...
}
Règles de composition:
class OrRule: IRule {
private readonly IRule[] rules;
public OrRule(params IRule[] rules) {
this.rules = rules;
}
public isSatisfied(thing: Thing) {
return this.rules.Any(r => r.isSatisfied(thing));
}
}
class AndRule: IRule {
private readonly IRule[] rules;
public AndRule(params IRule[] rules) {
this.rules = rules;
}
public isSatisfied(thing: Thing) {
return this.rules.All(r => r.isSatisfied(thing));
}
}
// Helpers for AndRule / OrRule
static IRule and(params IRule[] rules) {
return new AndRule(rules);
}
static IRule or(params IRule[] rules) {
return new OrRule(rules);
}
Une méthode de service qui exécute une règle sur une chose:
class SomeService {
public evaluate(IRule rule, Thing thing) {
return rule.isSatisfied(thing);
}
}
Usage:
// Compose a tree of rules
var rule =
and (
new Rule1(),
or (
new Rule2(),
new Rule3()
)
);
var thing = new Thing();
new SomeService().evaluate(rule, thing);
Cela a également été répondu ici: https://softwareengineering.stackexchange.com/questions/323018/business-rules-design-pattern
Quelque chose qui pourrait aider est un moteur de règles comme Drools . Ce n'est pas un modèle de conception, donc ce n'est peut-être pas la réponse que vous recherchez. Mais l'OMI, vous devriez y penser. Voici un excellent article sur quand vous devez utiliser un moteur de règles .
Un modèle de conception peut vous aider à rendre le code plus lisible ou à améliorer sa maintenabilité, mais si vous avez vraiment besoin d'évaluer un tel nombre de conditions, les instructions IF ne peuvent pas être évitées.
J'envisagerais de voir le problème d'un autre point de vue (par exemple: ai-je vraiment besoin d'une centaine d'instructions conditionnelles pour résoudre le problème?) Et j'essaierais de changer ou d'améliorer le algorithme
Un Expression Language pourrait fournir une aide car vous pouvez créer par programme une chaîne qui représente chaque instruction IF et évaluer le résultat à l'aide de cet outil, mais vous devez toujours résoudre le problème lié à l'exécution du particulier logique associée à chaque condition.
Une démo de stratégie simple avec python:
class Context(object):
def __init__(self, strategy):
self.strategy = strategy
def execute(self, num1, num2):
return self.strategy(num1, num2)
class OperationAdd(object):
def __call__(self, num1, num2):
return num1 + num2
class OperationSub(object):
def __call__(self, num1, num2):
return num1 - num2
if __name__ == '__main__':
con = Context(OperationAdd())
print "10 + 5 =", con.execute(10, 5)
con = Context(OperationSub())
print "10 - 5 =", con.execute(10, 5)