首页 > 解决方案 > 用于强制类先决条件的java设计模式

问题描述

我想知道在施工时强制执行全类先决条件的最佳设计是什么。

让我举一个简化的例子。

我有一个代表安全字符串的类,例如密码。密码仅存储为其哈希表示。无法检查密码,而只能根据尝试的值进行检查。

class Password {
  private String passwordHash;
  private Password(){};
  public Password(String aPassword) {
    setPassword(aPassword);
  }
  public void setPassword(String aPassword) {
     passwordHash = hash(aPassword); 
  }
  public boolean checkPassword(String attempt) {
     return verify(attempt, passwordHash);
  }
} 

问题是如何设计哈希算法的选择。客户端代码必须能够从不同的哈希算法中进行选择。而且,在给定的应用程序中,所有密码都必须使用相同的哈希算法。

所以,我定义了一个Hasher接口,

interface Hasher {
  String hash(String password);
  boolean verify(String attempt, String hash);
}

可能有不同的 Hasher 实现。

class SimpleHasher implements Hasher {
  public String hash(String password) {  // native java String.hashCode()  
    return Integer.toString(password.hashCode(),16);
  }
  public boolean verify(String attempt, String hash) {
    return attempt.hashCode()==Integer.valueOf(hash, 16);
  }  
}

class SecureHasher implements Hasher {
  public String hash(String password) {  // Secure SCrypt hash
    return com.lambdaworks.crypto.SCryptUtil.scrypt(password,16384,8,1);
  }
  public boolean verify(String attempt, String hash) {
    return com.lambdaworks.crypto.SCryptUtil.check(attempt,hash);
  }
}

客户端代码必须选择一个实现并设置散列器。在那之前,没有人可以实例化密码。并且一旦设置,哈希就无法更改。

这是设计决策。

目前,我声明了一个static private变量,因此所有 Password 实例的哈希值都是相同的;并设置了一个强制它不能更改一次的设置器。

class Password {
  static private Hasher hasher = null;
  static public void setHasher(Hasher ahasher) throws Exception {
    if (hasher!=null) throw new Exception("hasher cannot be changed");
    hasher = ahasher;
  } 
  ....      

并且构造函数确保设置了哈希

class Password {
   ...    
   public Password(String aPassword) throws Exception {
     if (hasher==null) throw new Exception("no hasher set yet");  
     setPassword(aPassword);
   } 
   ...       

到目前为止,一切都很好。但是,在我看来,它看起来不太好。我想知道是否有一些常见的模式来解决这个问题。所以我的问题是这种模式是否存在以及如何在我的案例中实现它。

标签: javadesign-patterns

解决方案


我建议更改您的设计并尝试以不同的方式处理它。首先,做一些重构。构造函数不应包含任何代码。其次,您制作哈希器的接口很棒。不过,我会将其重构为:

public interface Hash {
    String hashed(String value);
    boolean isValid(String hashed);
}  

接下来,更改您的密码类:

public class Password {

    private String password;
    private Hash hash;

    public Password(String password, Hash hash) {
        this.password = password;
        this.hash = hash;
    }

    public boolean isValid(String password) {
       return hash.hashed(this.password).equals(hash.hashed(password);
    }
}

那将是一个优雅的设计。您只需要确保通过构造函数传递正确的哈希实现。一旦设置好,每个密码都将被验证为相同的实现。


推荐阅读