sintaxis - reglas de programacion en java
Patrón de diseño para implementar reglas de negocios con cientos de, si no, en java (6)
Tengo que implementar ciertas reglas comerciales con cientos de líneas de código a continuación
if this
then this
else if
then this
.
. // hundreds of lines of rules
else
that
¿Tenemos algún patrón de diseño que pueda implementarlo de manera efectiva o reutilizar el código para que se pueda aplicar a todas las reglas diferentes? Escuché sobre el patrón de especificación que crea algo como abajo.
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);
}
}
Y luego la implementación de los métodos Is, And, Or, pero creo que esto no puede salvarme escribiendo el "if" (puede que mi comprensión sea incorrecta) ...
¿Hay algún mejor enfoque para implementar tales reglas de negocios con tantas declaraciones en caso contrario?
EDITAR: Solo un ejemplo de ejemplo. A, B, C, etc. son propiedades de una clase. Aparte de esto, hay muchas otras reglas similares. Quiero hacer un código genérico para esto.
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>
Algo que podría ayudar es un motor de reglas como Drools . Sin embargo, no es un patrón de diseño, por lo que puede que esta no sea la respuesta que está buscando. Pero en mi opinión, deberías considerarlo. Aquí hay un gran artículo sobre cuándo debes usar un motor de reglas .
Debería consultar el patrón de diseño de reglas http://www.michael-whelan.net/rules-design-pattern/ . Parece muy similar al código de ejemplo que proporcionó y consiste en una interfaz base que define un método para determinar si una regla se cumple y luego varias implementaciones concretas por diferentes reglas. Como lo entiendo, su declaración de cambio se convertiría en una especie de bucle simple que solo evalúa las cosas hasta que su composición de reglas esté satisfecha o falle.
interface IRule {
bool isSatisfied(SomeThing thing);
}
class RuleA: IRule {
public bool isSatisfied(SomeThing thing) {
...
}
}
class RuleA: IRule {
...
}
class RuleC: IRule {
...
}
Reglas de composición:
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);
}
Algún método de servicio que ejecuta una regla en una cosa. class SomeService {public eval (regla IRule, Thing thing) {return rule.isSatisfied (thing); }}
Uso:
// Compose a tree of rules
var rule =
and (
new Rule1(),
or (
new Rule2(),
new Rule3()
)
);
var thing = new Thing();
new SomeService().evaluate(rule, thing);
Esto también fue respondido aquí: https://softwareengineering.stackexchange.com/questions/323018/business-rules-design-pattern
El patrón de estrategia podría ser útil aquí. Por favor marque Reemplazar lógica condicional con estrategia
Puedes usar el patrón de Comando o el patrón de Fábrica .
El patrón de comando se puede usar para reemplazar el interruptor engorroso / si los bloques tienden a crecer indefinidamente a medida que agrega nuevas opciones.
public interface Command {
void exec();
}
public class CommandA() implements Command {
void exec() {
// ...
}
}
// etc etc
luego cree un objeto Map<String,Command>
y llénelo con instancias de Command:
commandMap.put("A", new CommandA());
commandMap.put("B", new CommandB());
entonces puede reemplazar su if / else if chain con:
commandMap.get(value).exec();
En Factory Pattern incluye su if / switch en una Factory que cuida la fealdad y oculta la abundancia de ifs. Código de ejemplo para Factory Pattern .
Un patrón de diseño podría ayudarlo a hacer que el código sea más legible o mejorar su capacidad de mantenimiento, pero si realmente necesita evaluar ese número de condiciones, las declaraciones IF no se pueden evitar.
Consideraría ver el problema desde otro punto de vista (por ejemplo: ¿realmente necesito cien sentencias condicionales para resolver el problema?) Y trataría de cambiar o mejorar el algorithm.
Un lenguaje de expresión podría proporcionarle ayuda porque podría crear mediante programación una cadena que represente cada instrucción IF y evaluar el resultado utilizando esta herramienta, pero aún tiene que resolver el problema relacionado con la ejecución de la lógica particular asociada con cada condición.
Una demostración de estrategia simple con 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)