如何确保我的地图在我的构建器模式中设置后永远不会被修改?
How to make sure my map is never modified once set in my Builder pattern?
下面是我在我的一个项目中使用的构建器模式,我想让它在多线程环境中是线程安全的。一旦ClientKey
设置好,我不想让任何人再次修改它。
public final class ClientKey {
private final long userId;
private final int clientId;
private final long timeout;
private final boolean dataFlag;
// how can I make sure that my parameterMap is never modified once set
private final Map<String, String> parameterMap;
private ClientKey(Builder builder) {
this.userId = builder.userId;
this.clientId = builder.clientId;
this.remoteFlag = builder.remoteFlag;
this.dataFlag = builder.dataFlag;
this.parameterMap = builder.parameterMap;
this.timeout = builder.timeout;
}
public static class Builder {
protected final long userId;
protected final int clientId;
protected long timeout = 200L;
protected boolean remoteFlag = false;
protected boolean dataFlag = true;
protected Map<String, String> parameterMap;
public Builder(long userId, int clientId) {
this.userId = userId;
this.clientId = clientId;
}
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
return this;
}
public Builder remoteFlag(boolean remoteFlag) {
this.remoteFlag = remoteFlag;
return this;
}
public Builder dataFlag(boolean dataFlag) {
this.dataFlag = dataFlag;
return this;
}
public Builder addTimeout(long timeout) {
this.timeout = timeout;
return this;
}
public ClientKey build() {
return new ClientKey(this);
}
}
public long getUserId() {
return userId;
}
public int getClientId() {
return clientId;
}
public long getTimeout() {
return timeout;
}
public Map<String, String> getParameterMap() {
return parameterMap;
}
public boolean isDataFlag() {
return dataFlag;
}
}
在我上面的 ClientKey
中,有时我会在创建 ClientKey 对象时传递 parameterMap
,但有时它会为空。我们并不总是会设置parameterMap
。以下是我在我的应用程序代码中设置并传递 ClientKey 对象后在我的应用程序代码中迭代 parameterMap
的方式:
final Map<String, String> parameterMap = clientKey.getParameterMap();
if (!MapUtils.isEmpty(parameterMap)) {
Set<Entry<String, String>> params = parameterMap.entrySet();
for (Entry<String, String> e : params) {
url.append("&").append(e.getKey());
url.append("=").append(e.getValue());
}
}
问题是 - 我如何才能确保我的 parameterMap 在设置后不会在其间被修改。如您所见,一旦我构建了 ClientKey 对象,parameterMap 只会被读取而不会被修改。然而,它依赖于这样一个事实,即没有恶意或错误的客户端不会同时尝试修改,那么防止这种情况的最佳方法是什么?
如果要在创建 ClientKey
实例后防止对地图 contents 进行 any 修改,您应该在构造函数中使用它:
if (builder.parameterMap == null) {
this.parameterMap = null;
} else {
this.parameterMap = Collections.unmodifiableMap(builder.parameterMap);
}
如果您只想允许来自 ClientKey
代码的修改,而不是来自外部的修改,您应该 return 一个 unmodifiableMap()
in getParameterMap()
,但随后它不会是完全线程安全的——那么你必须使用 ConcurrentMap
。
在这种情况下,我建议使用 Guava 的 ImmutableMap
. I also suggest avoiding null
value for parameterMap
field and use an empty ImmutableMap
instead. For that you could also use its Builder
。
因此您的代码片段将变为:
public class ClientKey {
...
private final ImmutableMap<String, String> parameterMap;
public ClientKey(Builder builder) {
...
this.parameterMap = builder.parameterMap.build();
...
}
public static class Builder {
...
protected ImmutableMap.Builder<String, String> parameterMap = ImmutableMap.builder();
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap.putAll(parameterMap);
return this;
}
public Builder addParameter(String key, String value) {
this.parameterMap.put(key, value);
return this;
}
}
}
使用不可变映射将使 ClientKey
用户清楚地知道它不能被修改。
下面是我在我的一个项目中使用的构建器模式,我想让它在多线程环境中是线程安全的。一旦ClientKey
设置好,我不想让任何人再次修改它。
public final class ClientKey {
private final long userId;
private final int clientId;
private final long timeout;
private final boolean dataFlag;
// how can I make sure that my parameterMap is never modified once set
private final Map<String, String> parameterMap;
private ClientKey(Builder builder) {
this.userId = builder.userId;
this.clientId = builder.clientId;
this.remoteFlag = builder.remoteFlag;
this.dataFlag = builder.dataFlag;
this.parameterMap = builder.parameterMap;
this.timeout = builder.timeout;
}
public static class Builder {
protected final long userId;
protected final int clientId;
protected long timeout = 200L;
protected boolean remoteFlag = false;
protected boolean dataFlag = true;
protected Map<String, String> parameterMap;
public Builder(long userId, int clientId) {
this.userId = userId;
this.clientId = clientId;
}
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
return this;
}
public Builder remoteFlag(boolean remoteFlag) {
this.remoteFlag = remoteFlag;
return this;
}
public Builder dataFlag(boolean dataFlag) {
this.dataFlag = dataFlag;
return this;
}
public Builder addTimeout(long timeout) {
this.timeout = timeout;
return this;
}
public ClientKey build() {
return new ClientKey(this);
}
}
public long getUserId() {
return userId;
}
public int getClientId() {
return clientId;
}
public long getTimeout() {
return timeout;
}
public Map<String, String> getParameterMap() {
return parameterMap;
}
public boolean isDataFlag() {
return dataFlag;
}
}
在我上面的 ClientKey
中,有时我会在创建 ClientKey 对象时传递 parameterMap
,但有时它会为空。我们并不总是会设置parameterMap
。以下是我在我的应用程序代码中设置并传递 ClientKey 对象后在我的应用程序代码中迭代 parameterMap
的方式:
final Map<String, String> parameterMap = clientKey.getParameterMap();
if (!MapUtils.isEmpty(parameterMap)) {
Set<Entry<String, String>> params = parameterMap.entrySet();
for (Entry<String, String> e : params) {
url.append("&").append(e.getKey());
url.append("=").append(e.getValue());
}
}
问题是 - 我如何才能确保我的 parameterMap 在设置后不会在其间被修改。如您所见,一旦我构建了 ClientKey 对象,parameterMap 只会被读取而不会被修改。然而,它依赖于这样一个事实,即没有恶意或错误的客户端不会同时尝试修改,那么防止这种情况的最佳方法是什么?
如果要在创建 ClientKey
实例后防止对地图 contents 进行 any 修改,您应该在构造函数中使用它:
if (builder.parameterMap == null) {
this.parameterMap = null;
} else {
this.parameterMap = Collections.unmodifiableMap(builder.parameterMap);
}
如果您只想允许来自 ClientKey
代码的修改,而不是来自外部的修改,您应该 return 一个 unmodifiableMap()
in getParameterMap()
,但随后它不会是完全线程安全的——那么你必须使用 ConcurrentMap
。
在这种情况下,我建议使用 Guava 的 ImmutableMap
. I also suggest avoiding null
value for parameterMap
field and use an empty ImmutableMap
instead. For that you could also use its Builder
。
因此您的代码片段将变为:
public class ClientKey {
...
private final ImmutableMap<String, String> parameterMap;
public ClientKey(Builder builder) {
...
this.parameterMap = builder.parameterMap.build();
...
}
public static class Builder {
...
protected ImmutableMap.Builder<String, String> parameterMap = ImmutableMap.builder();
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap.putAll(parameterMap);
return this;
}
public Builder addParameter(String key, String value) {
this.parameterMap.put(key, value);
return this;
}
}
}
使用不可变映射将使 ClientKey
用户清楚地知道它不能被修改。