简体   繁体   中英

How to clean up repetitive if-statements

I'm currently investing a lot of time in cleaning up my code. I have a lot of If statements that handles my signup form in frontend.

I have a feeling that after reading the book "Clean code". That this is just ugly, however I didn't seem to find any "amazing/incredible" cleanup format for my code below.

lets say I have 15 more if-statements then this will cause a lot of duplicates, so are there any major improvements possible?

User userByUsername = userRepo.findByUsername(user.getUsername());
User userByEmail = userRepo.findUserByEmail(user.getEmail());
if (userByUsername != null && userByEmail != null) {
    throw new AccountException("Email and username already exist");
}
if (userByUsername != null) {
    throw new AccountException("Username already exist");
}
if (userByEmail != null) {
    throw new AccountException("Email already exist");
}

Another example with another method:

public void addConditions(ReservationDto reservationDto) {
    long roomId = roomService.findRoomByRoomName(reservationDto.getRoomName()).getRoomId();
    // Check for adding room: Roomcapacity for timeslote reached
    // If maxCapacityAfternoon reached, then only add to afternoon possible
    int roomCapacity = roomService.findRoomByRoomId(roomId).getCapacity();
    boolean maxCapacityMorning = roomCapacity <= getNumberOfReservationsForRoomByDateVoormiddag(roomId, reservationDto.getDate());
    boolean maxCapacityAfternoon = roomCapacity <= getNumberOfReservationsForRoomByDateNamiddag(roomId, reservationDto.getDate());
    boolean isMorning = reservationDto.isMorning();
    boolean isAfternoon = reservationDto.isAfternoon();
    capacityConditions(reservationDto, maxCapacityMorning, maxCapacityAfternoon);
    // Check: Reservation can only be made when it meets the following conditions
    // - Same user
    // - is active
    // - Morning and date overlap
    // - Afternoon and date overlap
    Reservation mappedReservation = mapReservationDto(reservationDto);
    int amountOfReservationsForDay = reservationRepo.existsReservationForDay(mappedReservation.getUsername(), mappedReservation.getDate());
    if (isMorning && isAfternoon) {
        if (amountOfReservationsForDay > 0) {
            throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
        }
        if (reservationRepo.existsReservationForMorning(mappedReservation.getUsername(), mappedReservation.getDate()) > 0
                || reservationRepo.existsReservationForAfterNoon(mappedReservation.getUsername(), mappedReservation.getDate()) > 0
        ) {
            throw new ServiceException(RESERVATION_MSG + "in de voor- of namiddag.");
        }
    }
    if (isMorning && !isAfternoon) {
        if (amountOfReservationsForDay > 0) {
            throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
        }
        if (reservationRepo.existsReservationForMorning(mappedReservation.getUsername(), mappedReservation.getDate()) > 0) {
            throw new ServiceException(RESERVATION_MSG + "in de voormiddag.");
        }
    }
    if (!isMorning && isAfternoon) {
        if (amountOfReservationsForDay > 0) {
            throw new ServiceException(RESERVATION_MSG + FOR_FULL_DAY + reservationDto.getDate());
        }
        if (reservationRepo.existsReservationForAfterNoon(mappedReservation.getUsername(), mappedReservation.getDate()) > 0) {
            throw new ServiceException(RESERVATION_MSG + "in de namiddag");
        }
    }
    if (!isMorning && !isAfternoon) {
        throw new ServiceException("Selecteer een tijdstip voor uw reservatie");
    }
}

As you can see my project has a lot of conditions when I want to add a reservation. These are only the add conditions and don't take into account the room capacity check. Which is a long list of If's as well

You could create an enum for all the data validation exceptions that can be thrown

public enum DataValidationError {
    USERNAME_EXISTS,
    EMAIL_EXISTS,
    ...
}

public static class AccountException extends Exception {
    private final List<DataValidationError> errors;

    public AccountException(List<DataValidationError> errors) {
        this.errors = errors;
    }

    public List<DataValidationError> getErrors() {
        return errors;
    }
}

Usage:

List<DataValidationError> errors = new ArrayList<>();

User userByUsername = userRepo.findByUsername(user.getUsername());
User userByEmail = userRepo.findUserByEmail(user.getEmail());

if (userByUsername != null) {
    errors.add(DataValidationError.USERNAME_EXISTS);
}
if (userByEmail != null) {
    errors.add(DataValidationError.EMAIL_EXISTS);
}
if (!errors.isEmpty()) {
    throw new AccountException(errors);
}

This way you could add as many errors in the enum and keep adding them to a list and throw it only once at the end.

I am not sure if any really major improvement can be applied here. But for example since you are throwing the same type of exception you might play around your error message and throw exception only once. Like:

if(userByEmail != null || userByUsername != null){
    String message = (userByEmail != null ? "Email" : "Username") + " already exist";
    if(userByEmail != null && userByUsername != null){
        message = "Email and username already exist";
    }
    throw new AccountException(message);
}

For make the code more extensible and close I would use a chain of validation for this kind of things. If you know about the SOLID principle, you have a problem of SRP and OCP. By implementing a chain of validation, you would have each node have one purpose and you could easily and more validation in the futur. After you just have to create a chain, The thing is that validation is ONE thing, so I would too create lost of tiny function with good names. so the reader can "escape early" the reading if needed.

Here is the design patern that could help you: https://refactoring.guru/design-patterns/chain-of-responsibility

I think you repository should thow those exceptions too. If you can't find a user throw an exception in your repository. You'll have less validation all over you code and it's easyer to read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM