我有一个关于在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。
有没有人有更好的想法重构这个?
如果您的使用模式是多次调用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>
的程度。一旦构造了谓词,就不需要进一步的输入。