samedi 15 juillet 2023

Rule Engine design with multiple predicates

I am trying to implement Rule engine desing pattern in my use case but not able to fit the pieces in the right place.

RuleEngine is where all rules are validated for a transaction before making it approved

public class RuleEngine {
    private Predicate<Transaction> predicates;

    private Transaction transaction;

    public void setTransaction(Transaction transaction){
        this.transaction = transaction;
    }

    public void addRules(Predicate<Transaction> predicates) {
        this.predicates = predicates;
    }

    public void executeRules() {
        if(predicates.test(transaction)) {
            // all rules are valided - payment success
        }
    }
}

Below Payments class is invoked by parent where transaction and its type are provided.

Then based on transaction, rules are added which is the difficult part.

Because of transactionUtils - hard dependency required to autowired, causing predicate chaining looks very ugly and seems not the correct way.

@Component
public class Payments {

    @Autowired
    PredicateHelper predicateHelper;

    public void process(Transaction transaction, String type) {
        RuleEngine ruleEngine = new RuleEngine();
        ruleEngine.setTransaction(transaction);

        switch (type) {
            case "card" :
                ruleEngine.addRules(getCardRules());
                break;
            case "cash" :
                ruleEngine.addRules(getCashRules());
                break;
            default : log.error("Invalid case");
        }
        ruleEngine.executeRules();
    }

    private Predicate<Transaction> getCardRules(){
        return predicateHelper.rule1
                .and(predicateHelper.rule2)
                .and(predicateHelper.rule3);        // Predicate chaining 
    }

    private Predicate<Transaction> getCashRules(){
        return predicateHelper.rule1
                .and(predicateHelper.rule4)
                .and(predicateHelper.rule5);        // Predicate chaining
    }
}
@Component
public class PredicateHelper {

    @Autowired
    TransactionUtils transactionUtils;      // hard dependency - in house library

    public Predicate<Transaction> rule1 = transaction -> "rule1".equals(transactionUtils.getName(transaction));
    public Predicate<Transaction> rule2 = transaction -> "rule2".equals(transactionUtils.getName(transaction));
    public Predicate<Transaction> rule3 = transaction -> "rule3".equals(transactionUtils.getName(transaction));
    public Predicate<Transaction> rule4 = transaction -> "rule4".equals(transactionUtils.getName(transaction));
    public Predicate<Transaction> rule5 = transaction -> "rule5".equals(transactionUtils.getName(transaction));
}

Is there a ways to have better predicate chaining with this solution. Thanks in advance.

Aucun commentaire:

Enregistrer un commentaire