我对java.util.function.Predicate中IO操作的使用有疑问。请考虑以下示例:
public class ClientGroupFilter implements Predicate<Client> {
private GroupMapper mapper;
private List<String> validGroupNames = new ArrayList<>();
public ClientGroupFilter(GroupMapper mapper) {
this.mapper = mapper;
}
@Override
public boolean test(Client client) {
// this is a database call
Set<Integer> validsIds = mapper.getValidIdsForGroupNames(validGroupNames);
return client.getGroupIds().stream().anyMatch(validIds::contains);
}
public void permit(String name) {
validGroupNames.add(name);
}
}
正如您所看到的,此过滤器接受任意数量的服务器组名称,这些名称在测试特定客户端时由映射器解析。如果客户端拥有其中一个有效的服务器组,则返回true。
现在,当然,如果将过滤器应用于多个客户端,这是完全无效的,这是显而易见的。所以,重构让我想到了这个:
public class ClientGroupFilter implements Predicate<Client> {
private GroupMapper mapper;
private List<String> validGroupNames = new ArrayList<>();
private boolean updateRequired = true;
private Set<Integer> validIds = new HashSet<>();
public ClientGroupFilter(GroupMapper mapper) {
this.mapper = mapper;
}
@Override
public boolean test(Client client) {
if(updateRequired) {
// this is a database call
validIds = mapper.getValidIdsForGroupNames(validGroupNames);
updateRequired = false;
}
return client.getGroupIds().stream().anyMatch(validIds::contains);
}
public void permit(String name) {
validGroupNames.add(name);
updateRequired = true;
}
}
当然,性能要好得多,但我仍然不满意解决方案,因为我觉得java.util.function.Predicate不应该像这样使用。但是,我仍然希望能够提供快速解决方案来过滤客户端列表,而无需要求使用者将服务器组名称映射到其ID。
有没有人有更好的想法重构这个?
答案 0 :(得分:0)
如果您的使用模式多次调用permit
,然后再次使用Predicate<Client>
而不再调用permit
,则可以将收集validGroupNames
的代码与使用构建器编写谓词的代码:
class ClientGroupFilterBuilder {
private final GroupMapper mapper;
private List<String> validGroupNames = new ArrayList<>();
public ClientGroupFilter(GroupMapper mapper) {
this.mapper = mapper;
}
public void permit(String name) {
validGroupNames.add(name);
}
public Predicate<Client> build() {
final Set<Integer> validIds = mapper.getValidIdsForGroupNames(validGroupNames);
return new Predicate<Client>() {
@Override
public boolean test(Client client) {
return client.getGroupIds().stream().anyMatch(validIds::contains);
}
}
}
}
这会将validIds
的构建限制在构建Predicate<Client>
的位置。构造谓词后,无需进一步输入。