При проектировании чего-то подобного я столкнулся бы с этим решением с учетом двух шаблонов проектирования:
- Шаблон стратегии: для замены повторяющегося , если еще каждый раз, когда вам нужно оценить большеinstances.
- Шаблон декоратора: Попытка сделать каждое условие максимально настраиваемым.Они могут быть составлены (декорированы) для одного или нескольких предикатов.
С учетом этих двух шаблонов вы можете достичь чего-то подобного:
Сначала определите, какие условия будут идентифицировать данный экземпляр:
public enum InstanceType {
INSTANCE_TYPE_1(Condition::isOne, Condition::isTwo),
INSTANCE_TYPE_2(Condition::isOne, Condition::isThree),
...;
private List<Predicate<Condition>> evaluators;
@SafeVarargs
InstanceType(final Predicate<Condition>... evaluators) {
this.evaluators = Arrays.asList(evaluators);
}
public boolean evaluate(final Condition condition) {
return evaluators.stream().allMatch(it -> it.test(condition));
}
}
Затем вам следуетсвяжите каждую реализацию экземпляра с конкретным типом экземпляра:
@Component
public class InstanceOne implements Instance {
@Override
public InstanceType getType() {
return InstanceType.INSTANCE_TYPE_1;
}
}
Наконец, класс для конфигурации, в котором определяется отношение между типами и экземплярами как EnumMap
@Configuration
public class InstanceFactoryConfig {
@Autowired
private List<Instance> instances;
@Bean
public EnumMap<InstanceType, Instance> instancesMap() {
EnumMap<InstanceType, Instance> instanceEnumMap = new EnumMap<>(InstanceType.class);
instances.forEach(i -> instanceEnumMap.put(i.getType(), i));
return instanceEnumMap;
}
}
Таким образом, ваш InstanceFactory может бытьзаменено на что-то вроде этого:
public class InstanceFactory {
@Autowire
private final EnumMap<InstanceType, Instance> instancesMap;
public void getInstance(Condition condition) {
instancesMap.get(getInstanceType(condition)).doSomething();
}
private InstanceType getInstanceType(Condition condition) {
return Arrays.stream(InstancesType.values())
.filter(evaluator -> evaluator.evaluate(condition))
.findFirst().orElseThrow(() -> new RuntimeException("Instance type not found"));
}
}
Как видите, ваш InstanceFactory менее подвержен изменению.Это означает, что каждый раз, когда вам нужно добавить новую реализацию экземпляра, вам нужно только изменить перечисление InstanceType.Надеюсь, это поможет.