Вы можете использовать потоки для сопоставления ключа (конфигурация псевдонима) с ключом вашей карты (правила псевдонима). Вот что я выполнил:
class Matcher {
Map<Key, Value> rules;
Matcher(Map<Key, Value> rules)
{
this.rules = rules;
}
public Optional<Message> findMessage(Key configuration)
{
return rules.keySet().stream()
.filter(e -> e.required_enum_one == configuration.required_enum_one)
.filter(e -> e.required_enum_two == configuration.required_enum_two)
.filter(e -> ! e.optional_boolean_one.isPresent() || e.optional_boolean_one.equals(configuration.optional_boolean_one))
.filter(e -> ! e.optional_enum_two.isPresent() || e.optional_enum_two.equals(configuration.optional_enum_two))
.findFirst()
.map(e -> rules.get(e).message);
}
}
// Test
Matcher matcher = new Matcher(rules);
Key configuration1 = new Key(foo1, bar1, Optional.of(true), Optional.of(baz1));
System.out.println("configuration1: " + matcher.findMessage(configuration1));
Key configuration2 = new Key(foo1, bar1, Optional.of(true), Optional.of(baz2));
System.out.println("configuration2: " + matcher.findMessage(configuration2));
Key configuration3 = new Key(foo1, bar2, Optional.of(false), Optional.of(baz2));
System.out.println("configuration3: " + matcher.findMessage(configuration3));
Key configuration4 = new Key(foo2, bar2, Optional.of(true), Optional.of(baz1));
System.out.println("configuration4: " + matcher.findMessage(configuration4));
Key configuration5 = new Key(foo2, bar1, Optional.of(true), Optional.of(baz1));
System.out.println("configuration5: " + matcher.findMessage(configuration5));
Вывод:
configuration1: Optional[Message=msg1]
configuration2: Optional[Message=msg2]
configuration3: Optional[Message=msg3]
configuration4: Optional[Message=msg4]
configuration5: Optional.empty
Вот стандартный код со всеми определениями классов и инициализацией объектов для запуска примера:
class EnumBar {
}
class EnumFoo {
}
class EnumBaz {
}
class Message {
String text;
Message(String text) {
this.text = text;
}
public String toString() {
return "Message=" + text;
}
}
class Key {
EnumFoo required_enum_one;
EnumBar required_enum_two;
Optional<Boolean> optional_boolean_one;
Optional<EnumBaz> optional_enum_two;
Key(EnumFoo required_enum_one, EnumBar required_enum_two,
Optional<Boolean> optional_boolean_one, Optional<EnumBaz> optional_enum_two) {
this.required_enum_one = required_enum_one;
this.required_enum_two = required_enum_two;
this.optional_boolean_one = optional_boolean_one;
this.optional_enum_two = optional_enum_two;
}
}
class Value {
Message message;
Value(Message message) {
this.message = message;
}
}
EnumBar bar1 = new EnumBar();
EnumBar bar2 = new EnumBar();
EnumFoo foo1 = new EnumFoo();
EnumFoo foo2 = new EnumFoo();
EnumBaz baz1 = new EnumBaz();
EnumBaz baz2 = new EnumBaz();
Message msg1 = new Message("msg1");
Message msg2 = new Message("msg2");
Message msg3 = new Message("msg3");
Message msg4 = new Message("msg4");
Optional<Boolean> anyBooleanValue = Optional.empty();
Optional<EnumBaz> anyBazValue = Optional.empty();
final Map<Key, Value> rules = new HashMap<>();
rules.put(new Key(foo1, bar1, Optional.of(true), Optional.of(baz1)), new Value(msg1));
rules.put(new Key(foo1, bar1, Optional.of(true), anyBazValue), new Value(msg2));
rules.put(new Key(foo1, bar2, anyBooleanValue, anyBazValue), new Value(msg3));
rules.put(new Key(foo2, bar2, anyBooleanValue, anyBazValue), new Value(msg4));
Есть только один недостаток: карта представляет собой неупорядоченный список записей, поэтому, если вы возьмете keySet и проведете через него поток, второе правило может быть оценено перед первым правилом. (Это означает, что в нашем примере configuration1 может выводить сообщение 2). Это просто проблема синхронизации с потоками и проблема реализации с наборами.
Вы можете исправить это, используя упорядоченный список вместо карты, но тогда вы не сможете оценить все правила параллельно, чтобы сохранить производительность (это означает использование «.parallelStream ()» вместо «.stream ()»). У меня есть идея получше: просто добавьте поле приоритета к своим правилам (Key-Class). Затем вместо применения ".first ()" используйте ".max (...)" относительно приоритета.