Вначале я бы предложил вам шаблон проектирования Спецификация , который:
- это конкретный шаблон проектирования программного обеспечения, в котором бизнес-правила могут быть объединены путем объединения бизнес-правил.вместе, используя булеву логику.Шаблон часто используется в контексте доменного дизайна.
, но ваш реальный код не совсем подходит для этого, так как вы не вызываете тот же метод хранилища в зависимости от случая.
Так что я думаю, что у вас есть два пути:
1) Рефакторинг вашего хранилища, чтобы обеспечить единый общий метод, принимающий параметр спецификации и способный обрабатывать разные случаи.
Если вы используете Spring,вы могли бы взглянуть на интерфейс JpaSpecificationExecutor
, который предоставляет такие методы, как:
List<T> findAll(Specification<T> spec)
Даже если вы не используете Spring, я думаю, что эти примеры могут вам помочь.
2) Если вы не можете реорганизовать хранилище, вам следует искать другой путь и указать уровень абстракции, относительно которого могут передаваться методы / параметры хранилища.
На самом деле вы вызываете другой метод с другими параметрами в соответствии с входными параметрами, но в любом случае вы возвращаете объекту того же типа объект клиента метода: Foo
.Таким образом, чтобы избежать условных выражений, полиморфизм - это способ следовать.
Каждый случай для обработки, в конечном итоге, представляет собой отдельную стратегию.Таким образом, у вас может быть интерфейс стратегии, и вы можете определить стратегию, которая будет использоваться для возврата Foo клиенту.
Кроме того, как предлагается в комментарии: a!=null && !a.isEmpty()
повторение несколько раз не является хорошим запахом.Это делает много дублирования, а также делает код менее читабельным.Было бы лучше применить эту обработку, используя такую библиотеку, как Apache common или даже собственный метод.
public class FooService {
private List<FindFooStrategy> strategies = new ArrayList<>();
public FooService(){
strategies.add(new FindFooByAAndBAndCStrategy());
strategies.add(new FindFooByBAndCStrategy());
strategies.add(new FindFooByAAndCStrategy());
strategies.add(new FindFooByCStrategy());
}
public Foo getFoo(String a, String b, String c){
for (FindFooStrategy strategy : strategies){
if (strategy.isApplicable(a, b, c)) {
return strategy.getFoo(a, b, c);
}
}
}
}
Где FindFooStrategy
определяется как:
public interface FindFooStrategy{
boolean isApplicable(String a, String b, String c);
Foo getFoo(String a, String b, String c);
}
И где каждый подкласс определяет свои правила.Например:
public class FindFooByAAndBAndCStrategy implements FindFooStrategy{
public boolean isApplicable(String a, String b, String c){
return StringUtils.isNotEmpty(a) && StringUtils.isNotEmpty(b) &&
StringUtils.isNotEmpty(c);
}
public Foo getFoo(String a, String b, String c){
return repository.findByAAndBAndC(a,b,c);
}
}