设置类变量的最佳方法是什么?该变量是基于Java中依赖枚举的一些条件逻辑的枚举?

时间:2018-10-10 00:53:08

标签: java enums java-8

我试图根据某些计算或条件逻辑将值从一个枚举映射到另一个枚举,而这些逻辑需要为类变量设置正确的枚举值。如何在不使用太多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 :(得分:3)

首先,将isSuperCarisCrazyGood方法移到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语句中使用布尔表达式即可。

答案 1 :(得分:3)

如果品牌和引擎的映射是一对一的,则可以执行以下操作:

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语句。当然,这取决于您要确切执行的操作,并且由于没有提供太多信息,因此我无法给出最佳答案。希望对您有帮助。

答案 2 :(得分:3)

使用我所说的谓词看起来像这样:

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

您创建一个包含谓词和结果的列表,并使用流,过滤器和findFirst遍历列表并找到正确的结果。如果条件比您简单,则不需要谓词并对其进行一些测试。

答案 3 :(得分:0)

我可能会将品牌存储在Car类中,但这是另一个问题。我将在Car类中有一个静态映射,用于跟踪每个品牌使用的引擎(如Ralf Renz所建议的那样):

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

答案 4 :(得分:-1)

使用谓词,条件(品牌,引擎,条件)创建枚举,并在其中提供条件。之后:

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

,您可以在需要新条件时随时更新Enum。它也会按照Enum的顺序进行,因此您可以使用它