在java.util.function.Predicate中执行IO操作

时间:2018-01-03 16:14:17

标签: java

我对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。

有没有人有更好的想法重构这个?

1 个答案:

答案 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>的位置。构造谓词后,无需进一步输入。