我有这样的代码:
Map<String, String> args = new HashMap<>();
args.put("-T", "Tom Sawyer");
// args.put("-I", "1112223334");
if (args.containsKey("-T")) {
Book book = libraryService.findBookByTitle(args.get("-T"));
} else {
Book book = libraryService.findBookByIsbn(args.get("-I"));
}
LibraryService:
public class LibraryService {
private final BookRepository bookRepository = new BookRepository();
public Book findBookByTitle(String title) {
return bookRepository.findByTitle(title);
}
public Book findBookByIsbn(String isbn) {
return bookRepository.findByIsbn(isbn);
}
BookRepository:
public class BookRepository {
private List<Book> books = new ArrayList<>();
public Book findByIsbn(String isbn) {
return books.stream()
.filter(s -> s.getIsbn().equals(isbn))
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
public Book findByTitle(String title) {
return books.stream()
.filter(s -> s.getTitle().equals(title))
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
有没有一种干净的方法来避免ifs?我希望我的代码决定是否必须使用参数-I
或-T
。我处理args
没有任何情况时的情况,我只是简化了StackOverflow的代码。我在代码中多次使用findByTitle和findByIsbn方法,所以我不确定另一种方法是否适合这里。
答案 0 :(得分:3)
不是将参数传递给存储库,而是将完整的Predicate
传递给它:
public class findOneByPredicate(Predicate<Book> filter) {
return books.stream()
.filter(filter)
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
然后你可以这样称呼它:
findOneByPredicte(b -> b.getIsbn().equals("ISBN"));
答案 1 :(得分:2)
实际上,代码似乎是最简单的,可能是最好的形式。
但是,您可以使用“书籍查找器”的映射来删除显式的if块。这是使用供应商的一个版本:
Map<String, Function<String, Book>> resolvers = new HashMap<>();
resolvers.put("-T", libraryService::findBookByTitle);
resolvers.put("-I", libraryService::findBookByIsbn);
然后可以在所有可能键的短流中使用:
Book book = Stream.of("-T", "-I").filter(args::containsKey)
.findFirst()
.map(key -> resolvers.get(key).apply(args.get(key)))
.orElse(null);
如果地图中既不null
也不-T
,则上述内容将返回-I
。
答案 2 :(得分:1)
你的代码看起来很不错,至少对我而言。
您的if语句不需要删除。它们没有重复,所以请保留它们。
另一方面,我确实在findBy
方法中找到了一些重复的代码:
public Book findByIsbn(String isbn) {
return books.stream()
.filter(s -> s.getIsbn().equals(isbn))
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
public Book findByTitle(String title) {
return books.stream()
.filter(s -> s.getTitle().equals(title))
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
您可以编写一个名为findBy
的新方法:
private Book findBy<T>(Function<Book, T> selector, T value) {
return books.stream()
.filter(s -> selector.apply(s).equals(value))
.findFirst()
.orElseThrow(() -> new RuntimeException(NO_BOOKS_FOUND));
}
然后让findByIsbn
和findByTitle
致电findBy
:
public Book findByIsbn(String isbn) {
return findBy(Book::getIsbn, isbn);
}
public Book findByTitle(String title) {
return findBy(Book::getTitle, title);
}
答案 3 :(得分:0)
你可以摆脱两个组合模式的if。我还认为第一个块中的if与其周围的代码有些不同。另一个问题是,这不符合开放式原则。让我们说你想要另一种类型的搜索参数,如registernumber -R或其他什么。你必须触摸if语句,如果这变得越来越大,你可能会破坏一些东西。
所以让我们看看,如果没有
,那么很好的代码会是什么样子args.put("-T", "Tom Sawyer");
args.put("-I", "1112223334");
Book book = libraryService.findBook(args);
但这明显不适合开箱即用。但你可以用策略模式做类似的事情。
IBookFindStrategy {
Book findBook(string param)
}
class IsbnFindStrategy : IBookFindStrategy {
Book findBook(string param) {
// your repocall
}
}
class NameFindStrategy : IBookFindStrategy {
Book findBook(string param) {
// your repocall
}
}
现在您只需要在其他地方转换参数并在Factory中初始化正确的策略。 Factory可以将参数存储在Hashmap中,并使用param -T
调用它,它将为您提供NameFindStrategy
。像这样的东西
class StrategyFactory {
Hashtable<String, IBookFindStrategy > strategies;
public StrategyFactory() {
strategies = new HashMap<String, IBookFindStrategy >();
strategies.put("-T", new NameFindStrategy());
strategies.put("-I", new NameIsbnFindStrategy());
}
public IBookFindStrategy GetStrategy(string param) {
return strategies.get(param);
}
}
最后,你的主要看起来像这样:
StrategyFactory factory = new StrategyFactory();
IBookFindStrategy bookFinder = factory.getStrategy(args);
Book book = bookFinder.findBook(args);
我不是一个开发机器,我的java有点生疏,所以我有点懒,不能写下所有内容,但我希望你能得到这个概念。