Каков наилучший способ установить переменную класса, которая является перечислением, основанным на некоторой условной логике на зависимом перечислении в Java? - PullRequest
0 голосов
/ 10 октября 2018

Я пытаюсь отобразить значения из одного перечисления в другое на основе некоторого вычисления или условной логики, которую мне нужно выполнить, чтобы установить правильное значение перечисления для переменной класса.Как я могу сделать это, не используя слишком много if / else, операторов switch?

Enum BRAND {
 MINI, FERRARI, PAGANI
}

и другого перечисления

Enum ENGINE {
LEVEL1, LEVEL2, LEVEL3
}

И у меня есть такой класс:

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 ...;
 }
} 

Может быть несколько таких условий, которые необходимо проверить, чтобы установить значения, и я хочу избежать неприятных операторов if / else / switch, как показано выше.Есть ли более функциональный способ сделать это.

Ответы [ 5 ]

0 голосов
/ 23 октября 2018

создайте перечисление с предикатами, СОСТОЯНИЕ (марка, двигатель, состояние) и укажите свое состояние там.После этого:

Conditions.values().foreach(condition -> {
    condition.isApplicable(variblesDto) ? return condition.apply() : continue;
});

, и вы обновляете свой Enum каждый раз, когда вам нужно новое условие.Это также пойдет в порядке Enum, так что вы можете играть с этим

0 голосов
/ 19 октября 2018

Использование предикатов, как я уже сказал, будет выглядеть следующим образом:

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;
    }
}

Вы создаете список с предикатами и результатами и используете stream, filter и findFirst, чтобы просмотреть список и найти правильный результат.Если условия проще, чем вам, вам не нужны предикаты и проверьте их немного по-другому.

0 голосов
/ 17 октября 2018

Если сопоставление один на один для бренда и двигателя, вы можете сделать что-то вроде этого:

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;
    }
}

Другой вариант:

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;
    }
}

Если сопоставление неодин-к-одному, и вам нужно как-то динамически рассчитать движок на основе некоторых параметров, вы также можете использовать это:

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);
}

или что-то вроде этого, где у вас есть некоторые значения по умолчанию и переопределение только для особых случаев:

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;
    }
}

Существует множество возможностей использования только перечислений, которые я на самом деле предпочитаю усложнять в операторах if / else или switch.Конечно, это зависит от того, что именно вы хотите сделать, и так как не так много информации, я не могу дать лучший ответ.Надеюсь, что это поможет вам.

0 голосов
/ 18 октября 2018

Я бы, вероятно, сохранил бренд в классе Car, но это другая проблема.У меня была бы статическая карта в классе Car, которая отслеживает, какие двигатели идут с каждой маркой (как предложил Ральф Ренц ):

Class Car {

 int model;
 int year;
 Engine engine;
 static Map<Brand, Engine> carEngineMap = new HashMap<>();

 public static void setBrandEngine(Brand b, Engine e) {
   carEngineMap.put(b, e);
 }

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

   mycar.engine = carEngineMap.get(b);
 }

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

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

Затем вы поставили бы условияв отдельности для каждой марки, как

Car.setBrandEngine(Brand.FERRARI, Engine.LEVEL2);
Car.setBrandEngine(Brand.PAGANI, Engine.LEVEL1);
...
0 голосов
/ 11 октября 2018

Сначала переместите ваши методы isSuperCar и isCrazyGood в Brand, вместо того, чтобы они принимали параметр Brand.Вы также можете добавить статический фабричный метод к Engine, который инкапсулирует логику, которую вы пытаетесь кодировать.Это не исключает «неприятных операторов if / else / switch», но, вероятно, будет намного более читабельным.

Например:

public Car(Brand b) {
  this.engine = Engine.forBrand(b);
}

, а затем:

enum Engine {
  LEVEL1, LEVEL2, LEVEL3

  public static Engine forBrand(Brand b) {
    if (b.isSuperCar()) {
      return b.isCrazyGood() ? LEVEL1 : LEVEL2;
    }
    return LEVEL3;
  }
}

Обратите внимание, что ваш метод isSuperCar может быть просто:

return b.equals(Brand.FERRARI) || b.equals(Brand.PAGANI);

Нет необходимости писать if (...) return true; else return false; или что-то подобное - просто используйте логическое выражение в if заявление напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...