0

I have this if else code, I was wondering if there is more useful/intelligent way for writing it :

public void saveContent() throws Exception {
   if(book.isColored()) {
      book.setChoosen(“1234”);
   } else if (book.isAvailable()) {
      book.setChosen(“23498”);
   } else if (book.isAdults()) {
      book.setChosen(“0562”);
   } else {
      ReaderResponse response = reader.getReaderResponse();
      if (response != null) {
         book.setChosen(response.getName());
         }
      } else {
            book.setChosen(“4587”);
      }
   }
}

The method returns void.

11
  • well , switch could be better Commented Jan 7, 2019 at 13:13
  • @parladneupane how do you use switch on different attributes? Commented Jan 7, 2019 at 13:14
  • 5
    Just out of interest: Can't a book be colored, available and adult-only? We have available, colored adult-only books in my country. Commented Jan 7, 2019 at 13:15
  • 1
    If those booleans are exclusive, then it could be a single value with an enum, and therefore a switch. From their names, they don't sound as if they are, which makes me wonder if your if else code really makes a lot of sense. I mean, you care about whether or not the book is available only if it is not colored? Commented Jan 7, 2019 at 13:16
  • 1
    As written, this wouldn't even compile. Your braces are messed up, and your last else is not attached to any if. Commented Jan 7, 2019 at 13:23

7 Answers 7

5

The introduction of a local variable in the middle of this causes problems. One way of dealing this is introducing another method - don't be afraid of small methods.

public void saveContent() throws Exception {
    book.setChoosen(
        book.isColored()   ? “1234"  :
        book.isAvailable() ? “23498” :
        book.isAdults()    ? “0562”  :
        readerResponse()
    );
}
private String readerResponse() throws Exception {
    ReaderResponse response = reader.getReaderResponse();
    return response == null ? “4587” : response.getName();
}

? : is the conditional operator, often referred to as the ternary operator.

In the event that getReaderResponse has no side-effect, you could repeat the call. get methods typically do not have side-effects, but I get the feeling here this one may well do. I am not sure where the Exception is thrown - I assume that is intended to be replace with a subtype.

Sign up to request clarification or add additional context in comments.

2 Comments

Very nice. How about Optional.ofNullable(reader.getReaderResponse).map(r -> r.getName()).orElse("4587")?
Not at all, just wanted to suggest. Your "long" way might indeed be more readable.
2

I wouldn't say this is more efficient, more useful or smarter way of doing the same, but certainly I think the code will be cleaner and testable by delegating the actual choosen code resolution to a different method:

public void saveContent() throws Exception {
   String choosenCode = getChoosenCode(book);
   book.setChoosen(choosenCode);
}

static String getChoosenCode(Book book) throws Exception {
   if (book.isColored()) {
      return “1234”;
   }
   if (book.isAvailable()) {
      return “23498”;
   }
   if (book.isAdults()) {
      return “0562”;
   }
   ReaderResponse response = reader.getReaderResponse();
   return (response != null) 
      ? response.getName()
      : “4587”;
}

As you can see there is no need of endless if-else blocks because of the early return approach. This also provides the ability to unit-test the choosen code part, which is a little more complicated if you have a void returning method.

Comments

1

You can implement Strategy Design Pattern as an alternative to if-else construction

2 Comments

I tend to like Strategy Pattern a lot. Don't you think it will be overkill for such a simple case ?
Maybe you're right, but strategy bases on lightweight classes. It will not have much impact.
0

Switch statement wouldn't help, because you're checking different kind of attributes. I'd use if statements but instead of "magical numbers" I'd use some static final constants. And I'd remove inside of last else statement into a separate method.

Comments

0

Well, this is a issue i´m thinking about for months. In my opinion it is not easy to write that code in a way it is smart and reabable for non senior programmers. A good way would be using a switch-statement, but this is not useable for boolean statements.

I would use the code as mentioned in the questions, but i´d move it to a single class/controller/service for more complex code (this would be better for testing complex behaviours).

Comments

0

Just wanted to add a Stream version, but I do not consider it adequate for just a handfull of cases.

List<Pair<Predicate<Book>, String>> mapping;
mapping.add(Book::isColored, "1234");
mapping.add(Book::isAvailable, "23498");
mapping.add(Book::isAdults, "0562");
ReaderResponse response = reader.getReaderResponse();
mapping.add((anyBook) -> response == null, "4587");

String chosen = mapping.stream()
        .filter(p -> p.getKey().test(book))
        .map(Pair::getValue)
        .findFirst()
        .orElseGet(response::getName);

Or

mapping.add((anyBook) -> true, response.getName());
mapping.stream()
        .filter(p -> p.getKey().test(book))
        .map(Pair::getValue)
        .findFirst()
        .ifPresent(book::setChose);

Comments

0

This doesn't implement your algorithm exactly (because there are some ambiguities) but demonstrates using an enum as a strategy pattern. In this form it is much easier to add/adjust the code because all special functionality of each book type is in it's own location (it's own enum).

Note that this also helps when a book can fall into several types (such as Coloured and Adult).

enum BookType {
    Coloured("1234"),
    Available("23498"),
    Adult("0562");

    private final String chosen;

    BookType(String chosen) {
        this.chosen = chosen;
    }

    public String getChosen() {
        return chosen;
    }

}

class Book {
    final Set<BookType> types = EnumSet.noneOf(BookType.class);
    Book book;

    public boolean hasType(BookType type) {
        return types.contains(type);
    }

    public void setChosen(String s) {

    }
}

public void saveContent() throws Exception {
    for(BookType type: BookType.values()) {
        if(book.hasType(type)) {
            book.setChosen(type.getChosen());
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.