DRY原则

DRY 原则

DRY 原则(Don’t Repeat Yourself):不要写重复的代码。

实现逻辑重复的代码不一定违反 DRY 原则

如:


  private boolean isValidUsername(String username) {
    // check not null, not empty
    if (StringUtils.isBlank(username)) {
      return false;
    }
    // check length: 4~64
    int length = username.length();
    if (length < 4 || length > 64) {
      return false;
    }
    // contains only lowcase characters
    if (!StringUtils.isAllLowerCase(username)) {
      return false;
    }
    // contains only a~z,0~9,dot
    for (int i = 0; i < length; ++i) {
      char c = username.charAt(i);
      if (!(c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.') {
        return false;
      }
    }
    return true;
  }

  private boolean isValidPassword(String password) {
    // 同isValidUsername()
  }

isValidUserName() 函数和 isValidPassword() 函数看起来明显违反 DRY 原则,
合并两个函数:

private boolean isValidUsernameOrPassword(String usernameOrPassword)

尽管代码的实现逻辑是相同的,但语义不同,我们判定它并不违反 DRY 原则。
对于包含重复代码的问题,我们可以通过抽象成更细粒度函数的方式来解决。

功能语义重复违反 DRY 原则

在同一个项目代码中有下面两个函数:isValidIp()checkIfIpValid()
尽管两个函数的命名不同,实现逻辑不同,但功能是相同的,都是用来判定 IP 地址是否合法的。

尽管两段代码的实现逻辑不重复,但语义重复,也就是功能重复,我们认为它违反了 DRY 原则。

代码执行重复违反 DRY 原则

如,UserServicelogin() 函数用来校验用户登录是否成功。
如果失败,就返回异常;如果成功,就返回用户信息。具体代码如下所示:


public class UserService {
  private UserRepo userRepo;//通过依赖注入或者IOC框架注入

  public User login(String email, String password) {
    boolean existed = userRepo.checkIfUserExisted(email, password);
    if (!existed) {
      // ... throw AuthenticationFailureException...
    }
    User user = userRepo.getUserByEmail(email);
    return user;
  }
}

public class UserRepo {
  public boolean checkIfUserExisted(String email, String password) {
    if (!EmailValidation.validate(email)) {
      // ... throw InvalidEmailException...
    }

    if (!PasswordValidation.validate(password)) {
      // ... throw InvalidPasswordException...
    }

    //...query db to check if email&password exists...
  }

  public User getUserByEmail(String email) {
    if (!EmailValidation.validate(email)) {
      // ... throw InvalidEmailException...
    }
    //...query db to get user by email...
  }
}

上面这段代码,既没有逻辑重复,也没有语义重复,但仍然违反了 DRY 原则。
这是因为代码中存在 执行重复

重构后的代码:


public class UserService {
  private UserRepo userRepo;//通过依赖注入或者IOC框架注入

  public User login(String email, String password) {
    if (!EmailValidation.validate(email)) {
      // ... throw InvalidEmailException...
    }
    if (!PasswordValidation.validate(password)) {
      // ... throw InvalidPasswordException...
    }
    User user = userRepo.getUserByEmail(email);
    if (user == null || !password.equals(user.getPassword()) {
      // ... throw AuthenticationFailureException...
    }
    return user;
  }
}

public class UserRepo {
  public boolean checkIfUserExisted(String email, String password) {
    //...query db to check if email&password exists
  }

  public User getUserByEmail(String email) {
    //...query db to get user by email...
  }
}