Java 如何避免if-else树代码?
我有一个rest控制器,它包含一个根据“title”和“author”参数查找书籍的方法 你能给我一些提示如何摆脱if-else结构吗? 现在并不复杂,但将来参数的数量可能会增加,这将导致混乱Java 如何避免if-else树代码?,java,spring,rest,Java,Spring,Rest,我有一个rest控制器,它包含一个根据“title”和“author”参数查找书籍的方法 你能给我一些提示如何摆脱if-else结构吗? 现在并不复杂,但将来参数的数量可能会增加,这将导致混乱 @GetMapping public ResponseEntity<List<Book>> searchBooksByTitleAndAuthor( @RequestParam(value = "title", required = fals
@GetMapping
public ResponseEntity<List<Book>> searchBooksByTitleAndAuthor(
@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "author", required = false) String author) {
if (title == null && author == null) {
log.info("Empty request");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else if (title != null && author == null) {
log.info("Retrieving books by title");
List<Book> books = bookService.getBooksByTitle(title);
if (books.isEmpty()) {
log.info("No books with this title");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
} else if (author != null && title == null) {
List<Book> books = bookService.getBooksByTitle(title);
if (books.isEmpty()) {
log.info("No books with this title");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
} else {
List<Book> books = bookService.getBooksByTitleAndAuthor(title, author);
if (books.isEmpty()) {
log.info("No books with matching this title and author");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
}
}
@GetMapping
公共响应Titleandautor提供的书目搜索(
@RequestParam(value=“title”,required=false)字符串标题,
@RequestParam(value=“author”,required=false)字符串(author){
if(title==null&&author==null){
log.info(“空请求”);
返回新的响应属性(HttpStatus.NO_内容);
}else if(title!=null&&author==null){
log.info(“按标题检索图书”);
List books=bookService.getBooksByTitle(title);
if(books.isEmpty()){
log.info(“没有此标题的书籍”);
返回新的响应属性(HttpStatus.NO_内容);
}
返回新的响应属性(books,HttpStatus.OK);
}else if(author!=null&&title==null){
List books=bookService.getBooksByTitle(title);
if(books.isEmpty()){
log.info(“没有此标题的书籍”);
返回新的响应属性(HttpStatus.NO_内容);
}
返回新的响应属性(books,HttpStatus.OK);
}否则{
List books=bookService.getbooksbytitleandautor(标题、作者);
if(books.isEmpty()){
log.info(“没有与此标题和作者匹配的书籍”);
返回新的响应属性(HttpStatus.NO_内容);
}
返回新的响应属性(books,HttpStatus.OK);
}
}
我只想写以下内容:
@GetMapping
public List<Book> searchBooksByTitleAndAuthor(@RequestParam String title, @RequestParam String author) {
return bookService.getBooksByTitleAndAuthor(title, author);
}
@GetMapping
公共列表SearchBooksByTitleandautor(@RequestParam字符串标题,@RequestParam字符串作者){
returnbookservice.getbooksbytitleandautor(标题、作者);
}
我将把响应属性
创建和HttpStatus
管理留给Spring。至于null
或空值管理,我将把它留给后面的服务或数据库查询
此外,您在RequestParam注释中编写的参数是默认值,可以简化
最后,为什么要记录所有查询?重点是什么?如果您的目标是生产,那么您的信息日志将被大量的查询垃圾发送,而且业务信息无论如何都不属于技术日志。没有很好的解决方案。如果我是你,我会将其重构为:
@GetMapping
public ResponseEntity<List<Book>> searchBooksByTitleAndAuthor(
@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "author", required = false) String author) {
List<Book> books;
if (StringUtils.isBlank(title) && StringUtils.isBlank(author)) {
log.info("Empty request");
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} else if (!StringUtils.isBlank(title) && !StringUtils.isBlank(author)) {
books = bookService.getBooksByTitleAndAuthor(title, author);
} else if (StringUtils.isBlank(author)) {
books = bookService.getBooksByTitle(title);
} else {
books = bookService.getBooksByAuthor(author);
}
if (books.isEmpty()) {
log.info("No books found with title = " + title + " and author = " + author);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
}
@GetMapping
公共响应Titleandautor提供的书目搜索(
@RequestParam(value=“title”,required=false)字符串标题,
@RequestParam(value=“author”,required=false)字符串(author){
列出书籍;
if(StringUtils.isBlank(标题)和&StringUtils.isBlank(作者)){
log.info(“空请求”);
返回新的响应属性(HttpStatus.BAD_请求);
}如果(!StringUtils.isBlank(标题)和&!StringUtils.isBlank(作者)){
books=bookService.getbooksbytitleandautor(标题、作者);
}else if(StringUtils.isBlank(author)){
books=bookService.getBooksByTitle(title);
}否则{
books=bookService.getBooksByAuthor(author);
}
if(books.isEmpty()){
log.info(“未找到标题为=“+title+”和作者为=“+author”的书籍);
返回新的响应属性(HttpStatus.NO_内容);
}
返回新的响应属性(books,HttpStatus.OK);
}
使用此解决方案,您将处理一次响应
一个提示
当没有发送参数时,返回一个错误的请求,说明此服务至少需要一个参数。由于您的计划是最终支持更多参数,您最好的选择可能是查看。这允许您动态构造查询。它不会避免使用
if
语句,但会避免使用else
语句,并使支持新参数变得非常容易。在存储库/DAO级别:
Criteria criteria = session.createCriteria(Book.class);
if (author != null && !author.isEmpty()) {
criteria.add(Restriction.eq("author", author));
}
if (title != null && !title.isEmpty()) {
criteria.add(Restriction.eq("title", title));
}
criteria.addOrder(Order.asc("publishDate"));
return (List<Book>) criteria.list();
Criteria=session.createCriteria(Book.class);
if(author!=null&&!author.isEmpty()){
标准.添加(限制.eq(“作者”,作者));
}
if(title!=null&&!title.isEmpty()){
标准。添加(限制。等式(“标题”,标题));
}
标准.addOrder(Order.asc(“publishDate”);
返回(列表)条件。列表();
这有一些显著的好处:
?排序=标题:asc&author=Bobby%20表格
另一个技巧是,一旦你输入了一定数量的参数(例如4-5个),创建一个简单的、好的对象来封装你的参数,这样就可以传递了。一点嵌套可能会有所帮助。 这将最大限度地减少重复测试。 一些代码:
if (StringUtils.isNotBlank(blam) || StringUtils.isNotBlank(kapow))
{
if (StringUtils.isBlank(blam))
{
// kapow is not blank.
}
else if (StringUtils.isBlank(kapow))
{
// blam is not blank.
}
else
{
// neither kapow nor blam is blank.
}
}
else
{
// both empty. error.
}
我喜欢布赖恩的答案,
但我永远不会推荐使用Hibernate。
MyBatis还支持条件where子句。我建议。它的灵感来自领域驱动的设计/模型,实现依赖于JPA标准,允许灵活地构建查询 下面是一个示例(未经测试,但您应该了解总体思路) BookSpec
public class BookSpecifications {
private BookSpecifications(){
}
public static Specification<Book> withAuthor(String author) {
return new Specification<Book>() {
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get("author"), author);
}
};
}
public static Specification<Book> withTitle(String title) {
return new Specification<Book>() {
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get("title"), title);
}
};
}
}
public class BookController {
@GetMapping
public ResponseEntity<List<Book>> searchBooksByTitleAndAuthor(
@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "author", required = false) String author) {
List<Book> books = bookService.findAll(title, author);
if (books.isEmpty()) {
log.info("No books with this specification ");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
}
}
public class BookService {
private BookRepository bookRepository;
public BookService(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
public List<Book> findAll(String title, String author) {
if (Stream.of(title, author)
.filter(s-> s == null || s.equals(""))
.count() == 0) {
return new ArrayList<>();
}
Specification<Book> specification = createSpecification(specification, title, () -> BookSpecifications.withTitle(title));
specification = createSpecification(specification, author, () -> BookSpecifications.withAuthor(author));
List<Book> books = bookRepository.findAll(specification);
return books;
}
Specification<Book> createSpecification(Specification<Book> currentSpecification, String arg, Callable<Specification<Book>> callable) {
// no valued parameter so we return
if (arg == null) {
return currentSpecification;
}
try {
// Specification instance already created : reuse it
if (currentSpecification != null) {
return currentSpecification.and(callable.call());
}
// Specification instance not created yes : create a new one
return callable.call();
} catch (Exception e) {
// handle the exception... if any
}
}
}
// existing
Specification<Book> specification = createSpecification(specification, title, () -> BookSpecifications.withTitle(title));
specification = createSpecification(specification, author, () -> BookSpecifications.withAuthor(author));
// change below !
specification = createSpecification(specification, anotherColumn, () -> BookSpecifications.withAnotherColumn(anotherColumn));
List<T> findAll(@Nullable Specification<T> spec);
@Repository
public interface BookRepository extends JpaRepository<Book, Long> , JpaSpecificationExecutor<Book> {
}
public class BookSpecifications {
private BookSpecifications(){
}
public static Specification<Book> withAttribute(String name, T value) {
return new Specification<Book>() {
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get(name), value);
}
};
}
}
private static long toKey(Object ... args) {
long key = 0L;
for(int i = 0; i < args.length; i++) {
if(args[i] != null) {
key |= (1L << i);
}
}
return key;
}
private static interface BookFinder {
ResponseEntity<List<Book>> search(String title, String author);
}
private static Map<Long, BookFinder> _keyToFinderMap = new HashMap<>();
static {
_keyToFinderMap.put(toKey(null, null), new BookFinder() {
public ResponseEntity<List<Book>> search(String title, String author) {
log.info("Empty request");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
});
_keyToFinderMap.put(toKey("", null), new BookFinder() {
public ResponseEntity<List<Book>> search(String title, String author) {
log.info("Retrieving books by title");
List<Book> books = bookService.getBooksByTitle(title);
if (books.isEmpty()) {
log.info("No books with this title");
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(books, HttpStatus.OK);
}
});
// Other cases
};
@GetMapping
public ResponseEntity<List<Book>> searchBooksByTitleAndAuthor(
@RequestParam(value = "title", required = false) String title,
@RequestParam(value = "author", required = false) String author) {
return _keyToFinderMap.get(toKey(title, author)).search(title, author);
}