1

Let's say I have few entity classes:

class EntityA { LocalDate date1; LocalDate date2; }
class EntityB { }
class EntityC { LocalDate date1; }

and I want to pass them through some logic containing lots of conditional checks. Simplified version of something like:

public class Predicate {

    public boolean test(EntityA a, EntityB b, EntityB c) {
            boolean aDate1Valid = isDateValid(a.getDate1());    
            boolean bExists = b != null;
            boolean cExists = c != null;

            return (aDate1Valid && bExists && cExists && isDateValid(c.getDate1()))
                    || (aDate1Valid && !bExists)
                    || (aDate1Valid && !cExists && isDateValid(a.getDate2()));
    }
}

currently I'm retrieving all entities in advance before executing the test() method:

public static void main(String[] args) {
    Predicate predicate = new Predicate();
    EntityA a = loadEntityAFromDB1();
    EntityB b = loadEntityBFromWebService1();
    EntityB c = loadEntityCFromWebService2();
    predicate.test(a, b, c);
}

The problem is loading all entities is quite expensive (it involves DB queries, few external API calls etc.) and my Predicate's logic doesn't necessarily need to check all of them - for example when isDateValid(a.getDate1()) is not true, then nothing else needs to be checked.

Is there any better way to design this to load required data in more lazy way and to keep my business logic clean from data access logic?

3 Answers 3

3

Yes, one alternative is to design your code around behavior instead of data.

What I mean is to implement some use-case specifically, without trying to be generic, or trying to re-use parts. Just implement the check where it needs to be with whatever specific tools, like webservice calls or database access, specifically tailored to the task at hand.

Generalizing data access to the point of being unable to optimize or use specific backend features is the problem. Don't generalize in advance. Do it when you need it, and only to the amount you need it.

More specifically: don't do "data" classes (you called them entities). Those by their nature try to be "generic", to fit multiple use-cases, or even be used across applications. Instead, have classes contain behavior (i.e. logic), that is not re-usable, but therefore much more easy to optimize and maintain.

0

I'd suggest passing a function as an argument instead of the bool, so that you can execute part a, then ONLY do parts b and c IF a evaluated to true. Something like:

public class Predicate {

public boolean test(Func<EntityA> a, Func<EntityB> b, Func<EntityB> c) {
        boolean aDate1Valid = isDateValid(a.Invoke().getDate1()); 
        if(!aDate1Valid) return false;
        boolean bExists = b.Invoke() != null;
        if(!bExists) return true; // second condition
        boolean cExists = c.Invoke() != null;

        return (aDate1Valid && bExists && cExists && isDateValid(c.getDate1()))
                //|| (aDate1Valid && !bExists) // second condition can be removed
                || (aDate1Valid && !cExists && isDateValid(a.getDate2()));
}

}

0

The test case is forcing you to load all entities in advance

  • You should not load all entities.
  • Load a
  • If date is valid then load b, else return
  • If b is valid then load c

If the test case is a real business requirement then wrap the entities in a class that loads them lazily. I hope the entities can be abstracted into an interface so you don't have to code multiple lazy wrappers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.