Java 作为一个库作者,期望用户根据情况将null传递给方法参数,这是一个糟糕的设计吗?
我正试图编写一个供外部用户使用的库,我被一些基本的设计决策所困扰 我正在编写一个简单的POJO类,它将包含一些关于OAuth2令牌的信息 此类课程需要满足以下条件:Java 作为一个库作者,期望用户根据情况将null传递给方法参数,这是一个糟糕的设计吗?,java,api-design,Java,Api Design,我正试图编写一个供外部用户使用的库,我被一些基本的设计决策所困扰 我正在编写一个简单的POJO类,它将包含一些关于OAuth2令牌的信息 此类课程需要满足以下条件: 如果令牌是永久令牌,则用户只需传递令牌 如果令牌是临时令牌,则用户需要传递令牌、expirationDate和refreshToken 永远不会出现只有expirationDate和refreshToken中的一个为空的情况。两者都将为null或都为非null 这就是我到目前为止所做的: public TokenInformat
- 如果令牌是永久令牌,则用户只需传递令牌
- 如果令牌是临时令牌,则用户需要传递令牌、expirationDate和refreshToken李>
- 永远不会出现只有expirationDate和refreshToken中的一个为空的情况。两者都将为null或都为非null
public TokenInformation(String token, Date expirationDate, String refreshToken) {
Objects.requireNonNull(token, "token parameter cannot be null.");
this.token = token;
if ((expirationDate != null) && (refreshToken != null)) {
this.expiresIn = expiresIn;
this.refreshToken = refreshToken;
isPermanentToken = false;
} else if ((expirationDate == null) && (refreshToken == null)) {
this.expiresIn = null;
this.refreshToken = null;
isPermanentToken = true;
} else {
// throw some exception here
}
}
老实说,我并不完全满意代码的外观
但我确实有以下想法:
- 有两个构造函数。一个仅具有一个参数(用于永久令牌),另一个具有所有三个参数(临时令牌)。但是,我担心的是,用户不会正确阅读文档,会使用永久令牌构造函数作为临时令牌
- 有两种不同的工厂方法,而不是构造函数。这些工厂方法将被清楚地命名,因此用户使用错误方法的可能性很小。此外,用户不会被强制显式传递null
不过我想听听其他人的意见。因此,如果您需要任何其他信息,请告诉我。我更愿意将永久和临时令牌行为封装到各自的域中,以便库中的任何用户都清楚地知道正在实例化哪种令牌 我认为建议的课程:
/**
* The base class encapsulates the behavior of generic token
*/
public class AbstractToken {
protected String token;
// other properties that exist very closely with token
public String getToken() {
return token;
}
}
永久令牌的域
/**
* The domain encapsulates the behaviour of Permanent token - token that never expires
*/
public class PermanentToken extends AbstractToken {
// more attributes that makes general token as Parmament token
/**
* Instantiates a new Permanent token - this token never expires
*
* @param token the token
*/
public PermanentToken(String token) {
this.token = token;
}
}
临时令牌的域:
/**
* The domain for Temporary token.
*/
public class TemporaryToken extends AbstractToken {
private Date expirationDate;
private String refreshToken;
// more attributes that makes general token as temporary token
/**
* Instantiates a new Temporary token with token expiry date and refresh token
*
* @param token the token
* @param expirationDate the expiration date
* @param refreshToken the refresh token
*/
public TemporaryToken(String token, Date expirationDate, String refreshToken) {
this.token = token;
this.expirationDate = expirationDate;
this.refreshToken = refreshToken;
}
}
现在库的用户清楚地知道他/她想要实例化和使用哪种令牌
附言-我想你可以为你的域名保留更好的名字
你也可以为你的图书馆做生意
基于上面的代码,我认为多构造函数方法比工厂方法更合适。有多个构造函数是一种非常常见的Java设计模式,用户可以在这些构造函数上传递他们确实有数据的字段的信息。构造函数不会复制代码,而是使用默认值相互调用
public TokenInformation(String token) {
this(token, null, null);
}
public TokenInformation(String token, Date expirationDate, String refreshToken) {
Objects.requireNonNull(token, "token parameter cannot be null.");
this.token = token;
if ((expirationDate != null) && (refreshToken != null)) {
this.expiresIn = expiresIn;
this.refreshToken = refreshToken;
isPermanentToken = false;
} else if ((expirationDate == null) && (refreshToken == null)) {
this.expiresIn = null;
this.refreshToken = null;
isPermanentToken = true;
} else {
// throw some exception here
}
}
由于您没有创建多种不同类型的TokenInformation
对象,因此我找不到适合您需要的工厂模式。如果你要使用一种模式,我会选择Builder而不是factory
编辑:我应该更好地阅读你的代码。我将在这里留下我的答案,因为我认为如果您不想更改您的类,我的解决方案仍然适用,但是,我认为@DHRUV BANSAL有更好的方法,因为您的令牌实际上代表不同的东西
在javadocs中阐明您的愿望并用先决条件强制执行它们应该很容易。罪恶在于让用户猜测你的意图。这是基于观点的。在我看来,您应该只创建有意义的消息签名;如果有一个版本中您要传入
null
s,那么您就有一个(字符串标记)
方法,以及一个所有内容都应该有值的方法。@duffymo我同意。然而,我也希望通过编程尽可能清楚地表达我的意图。有很多人浏览文档,这可能会导致一个滑坡,人们会感到不安,即使从技术上讲这是他们的错。如果可能的话,我想避免这种情况。@DaveNewton-我不同意这是基于观点的。我正在寻找标准的最佳实践。我希望了解普通Java程序员对他们使用的库的期望。最佳实践是根据定义提出的意见。