Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to set class variable which is an enum based on some conditional logic on a dependent enum in java?

Tags:

java

enums

java-8

I am trying to map values from one enum to the other based on some calculation or conditional logic that I need to perform to set the correct enum value for the class variable. How can I do this without using too many if/else, switch statements?

Enum BRAND {
 MINI, FERRARI, PAGANI
}

and another enum

Enum ENGINE {
LEVEL1, LEVEL2, LEVEL3
}

And I have a class like :

Class Car() {

 int model;
 int year;
 Engine engine;

 // I want to calculate set the engine depending on the brand based on conditional logic
 public carEngineCalculator (Brand b) {
   Car mycar = new Car();

   if (mycar.isSuperCar(b) {
    if (mycar.isCrazyGood(b)) {
        mycar.engine = ENGINE.LEVEL1;
    } else {
        mycar.engine = ENGINE.LEVEL2;
    }
   } else {
    mycar.engine = ENGINE.LEVEL3;
   }
   ... //And the conditions can be more complex
 }

 public boolean isSuperCar(Brand b) {
    if (b.FERRARI || b.PAGANI) {
     return true;
    } 
    return false;
 }

 public boolean isCrazyGood(Brand b) {
    return ...;
 }
} 

There can be more than one such conditions that need to be checked in order to set the values and I want to avoid nasty if/else/switch statements as shown above. Is there a more functional way of doing this.

like image 433
RamPrasadBismil Avatar asked Jan 27 '23 08:01

RamPrasadBismil


2 Answers

Using predicates as I said would look like this:

public enum Brand {
    MINI,
    FERRARI,
    PAGANI
}

public enum Engine {
    LEVEL1,
    LEVEL2,
    LEVEL3
}

public class Entry {
    public final Predicate<Car> pred;
    public final Engine engine;

    public Entry(Predicate<Car> pred, Engine engine) {
        this.pred = pred;
        this.engine = engine;
    }
}

public class Car {
    int model;
    int year;
    Engine engine;

    public void carEngineCalculator(Brand b) {
        Car mycar = new Car();

        List<Entry> cases = new ArrayList<>();
        cases.add(new Entry(c -> c.isSuperCar(b) && c.isCrazyGood(b), Engine.LEVEL1));
        cases.add(new Entry(c -> c.isSuperCar(b) && !c.isCrazyGood(b), Engine.LEVEL2));
        cases.add(new Entry(c -> !c.isSuperCar(b), Engine.LEVEL3));

        mycar.engine = cases.stream().filter(x -> x.pred.test(mycar)).findFirst().get().engine;

    }

    public boolean isSuperCar(Brand b) {
        if ((b == Brand.FERRARI) || (b == Brand.PAGANI)) {
            return true;
        }
        return false;
    }

    public boolean isCrazyGood(Brand b) {
        return false;
    }
}

You create a List with Predicates and Results and use stream, filter and findFirst to go through the list and find the right result. If the conditions are simpler than you don't need predicates and test it a little bit different.

like image 143
Ralf Renz Avatar answered Jan 31 '23 09:01

Ralf Renz


If the mapping is one-to-one for Brand and Engine, you could do something like this:

enum Brand {
    MINI(Engine.LEVEL1),
    FERRARI(Engine.LEVEL2),
    PAGANI(Engine.LEVEL3);

    private final Engine engine;

    private Brand(Engine engine) {
        this.engine = engine;
    }

    public final Engine getEngine() {
        return engine;
    }
}

Another option:

enum Brand {
    MINI(false, false),
    FERRARI(true, true),
    PAGANI(false, true);

    private final boolean superCar;
    private final boolean crazyGood;

    private Brand(boolean superCar, boolean crazyGood) {
        this.superCar = superCar;
        this.crazyGood = crazyGood;
    }

    public final Engine getEngine() {
        if (superCar) {
            return (crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
        }
        return Engine.LEVEL3;
    }
}

If the mapping is not one-to-one and you need to somehow dynamically calculate the engine based on some parameters, you could also use this:

enum Brand {
    MINI {
        @Override
        public Engine getEngine(boolean superCar, boolean crazyGood) {
            return (superCar && crazyGood) ? Engine.LEVEL1 : Engine.LEVEL2;
        }
    },
    FERRARI {
        @Override
        public Engine getEngine(boolean superCar, boolean crazyGood) {
            return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
        }
    },
    PAGANI {
        @Override
        public Engine getEngine(boolean superCar, boolean crazyGood) {
            return Engine.LEVEL3;
        }
    };

    public abstract Engine getEngine(boolean superCar, boolean crazyGood);
}

Or something like this, where you have some defaults and override just for special cases:

enum Brand {
    MINI,
    FERRARI {
        @Override
        public Engine getEngine(boolean superCar, boolean crazyGood) {
            return superCar ? Engine.LEVEL1 : Engine.LEVEL3;
        }
    },
    PAGANI;

    public Engine getEngine(boolean superCar, boolean crazyGood) {
        return Engine.LEVEL3;
    }
}

There are a lot of possibilities using just enums, which I actually prefer to complex if/else or switch statements. Of course it depends on what exactly you want to do and since there is not much info provided, I cannot really give the best answer. Hope that this helps you.

like image 34
Tomo Česnik Avatar answered Jan 31 '23 09:01

Tomo Česnik