Проверка классов модели в методах сеттера - PullRequest
3 голосов
/ 03 мая 2019

Я хотел бы спросить ваши идеи о разработке наилучшего подхода к валидации для следующих требований:

У нас есть User класс модели, и в зависимости от его статуса мы можем обновить некоторые конкретные поля. Как видите, изменчивость класса модели зависит от его поля состояния.

  • Если статус пользователя ACTIVE, то все поля (имя, фамилия, пароль ....) можно обновить.
  • Если статус пользователя INACTIVE, то только пароль может быть обновлен.
  • Если статус пользователя BLOCKED, то имя и фамилия могут быть обновлен.
  • Если статус пользователя DELETED, то операция обновления не разрешено для любого поля.

Очевидно, это можно сделать, просто добавив класс UserValidator, и перед установкой значений в методах установки я могу вызвать UserValidator, чтобы проверить, разрешена операция или нет. Однако у него есть недостаток (?): Что произойдет, если появится новое поле (скажем, maritalStatus), и разработчик, который добавляет это поле, забывает вызвать UserValidator перед установкой maritalStatus?

Другие способы решения этой проблемы, о которых я могу подумать:

  1. Использование пользовательских аннотаций путем расширения CustomValidator. Тем не менее, это не будет работать, так как аннотация не может знать предыдущие значения объекта. Я имею в виду, isValid() метод CustomValidator не будет знать, если имя поле изменилось или нет (это был "Джон", и теперь dev хочет изменить его «Джеку»)
  2. Прокси-шаблон может быть полезен, но не уверен, стоит ли его использовать прокси для модельных объектов.

Я видел, что шаблон декоратора может быть использован для этой проблемы, но я не понимаю, как. Я думаю, что проверка класса модели не входит в обязанности дизайнера декоратора.

public class User {
    private Integer id;
    private String name;
    private String surname;
    private String password;
    private Status status;
    // setters
}

public enum Status {
    ACTIVE, DELETED, INACTIVE, BLOCKED
}

Ответы [ 2 ]

1 голос
/ 03 мая 2019

Я предлагаю вам использовать открывающие намерение интерфейсы вместо setter / getter

* 1003 Е.Г. *

public class User {
   private Integer id;
   private String name;
   private String surname;
   private String password;
   private Status status;


   void rename(String newName, String newSurname){
      if(Status.INACTIVE.equals(status) || Status.DELETED.equals(status))
          throws new Exception("You cannot rename a inactive or deleted user");

      this.name = newName;
      this.surname = newSurname;
   }
    .....

}  
0 голосов
/ 09 мая 2019

Вот подход, который я буду использовать.Было бы очень хорошо, если бы вы, ребята, тоже могли проголосовать за это.

В основном я буду использовать шаблон Decorator.

public interface User {
    Integer getId();

    void setId(Integer id);

    String getName();

    void setName(String name);

    String getSurname();

    void setSurname(String surname);

    String getPassword();

    void setPassword(String password);

    Status getStatus();

    void setStatus(Status status);
}

public class UserImpl implements User {
    private Integer id;
    private String name;
    private String surname;
    private String password;
    private Status status;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }
}


public abstract class UserDecorator  implements User{

    private final User user;

    public UserDecorator(User user) {
        this.user = user;
    }


    public Integer getId() {
        return user.getId();
    }

    public void setId(Integer id) {
        user.setId(id);
    }

    public String getName() {
        return user.getName();
    }

    public void setName(String name) {
        user.setName(name);
    }

    public String getSurname() {
        return user.getSurname();
    }

    public void setSurname(String surname) {
        user.setSurname(surname);
    }

    public String getPassword() {
        return user.getPassword();
    }

    public void setPassword(String password) {
        user.setPassword(password);
    }

    public Status getStatus() {
        return user.getStatus();
    }

    public void setStatus(Status status) {
        user.setStatus(status);
    }
}

Неактивный пользователь:

public class InactiveUserImpl extends UserDecorator {
    public InactiveUserImpl(User user) {
        super(user);
    }
    // didn't override setPassword therefore that field can be updated when the status of user is Inactive

    @Override
    public void setId(Integer id) {
        throw new IllegalArgumentException("Field can not be update when user is InActive");
    }

    @Override
    public void setName(String name) {
        throw new IllegalArgumentException("Field can not be update when user is InActive");
    }

    @Override
    public void setSurname(String surname) {
        throw new IllegalArgumentException("Field can not be update when user is InActive");
    }

    @Override
    public void setStatus(Status status) {
        throw new IllegalArgumentException("Field can not be update when user is InActive");
    }
}

Активный пользователь:

public class ActiveUserImpl extends UserDecorator {
    public ActiveUserImpl(User user) {
        super(user);
    }

    // not overriding any method hence everything can be updated
}

В основном, кто бы ни попросил UserImpl, я верну ему упакованную версию UserImpl, например,

class UserRepository{

    public User getById(String id){
        User user=db.getUserById(id);

        // this can be done with Enum but it is out of our scope

        if (user.getStatus().equals(INACTIVE))
            return new InactiveUserImpl(user);
        // ....
        return null; 
    }
}

Если вы сделаете:

User user= userRepository.getById(1) 

тогда вы получите пользователя с наборами разрешенных сеттеров.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...