首页 > 解决方案 > 在 Java 中重用函数/类的一般方法

问题描述

我为较早的作业编写了GtfReader类。该类基本上读取一个特殊的 tsv 文件并将信息分类到类中。到现在为止还挺好。
现在下一个作业(已经完成)也需要一个 gtf 阅读器,所以我只是重用了旧作业中的那个。困扰我的是,这一次我不需要读者提取的所有信息。我正在为我不使用的东西浪费内存/性能,并且可以从一开始就将其过滤掉。

我的问题是如何修改类/函数以最佳地与两个项目一起工作?
在这种情况下,一般方法是什么?
我的计划是传递一个“模式”参数来决定是否需要额外的数据,但我怀疑这是一个好习惯。

这是一个例子:

public Map<String, List<String>> tsv_reader(String gtf_file) {
        Set<String> names = new HashSet<>();
        names.add("gene");
        names.add("transcript");
        try(Stream<String> s = Files.lines(Paths.get(gtf_file))){
            return s
                    .filter(line -> !line.startsWith("#") && !names.contains(line.split("\t")[2]))
                    .collect(Collectors.groupingBy(line -> StringUtils.substringBetween(
                            line.substring(0, line.indexOf(";")), "\"", "\"")));

        }
}

此函数提取文件的所有行,按唯一 ID 排序,由同一组的行共享。
现在假设我想添加一个要过滤的 ID 列表,但如果列表为空,它应该读取所​​有行。
这只是一个例子。我只想要一个针对这类问题的通用方法。

标签: java

解决方案


对于您的具体示例,只需添加一个参数来指定您感兴趣的内容:

// extracted for readability
private static String extractId(String line) {
    String start = line.substring(0, line.indexOf(";"));
    return StringUtils.substringBetween(start, "\"", "\""))
}

public Map<String, List<String>> tsvReader(String gtfFileName, Predicate<String> validIds) {
    Set<String> badKeys = new HashSet<>();
    badKeys.add("gene");
    badKeys.add("transcript");
    try (Stream<String> s = Files.lines(Paths.get(gtfFileName))){
        return s
                .filter(line -> !line.startsWith("#") 
                           && !badKeys.contains(line.split("\t")[2]
                           && validIds.test(extractId(line)))
                .collect(Collectors.groupingBy(line -> extractId(line)));

    }
}

要使用,只需传递一个谓词,该谓词将对 ID 执行额外的过滤器。或者传递一个空谓词来保持旧的非 id 过滤行为:

tsvReader("foo.gtf", id -> Integer.parseInt(id) < 100); // returns 1st 100 ids
tsvReader("foo.gtf", id -> goodIdSet.contains(id)); // using a map
tsvReader("foo.gtf", id -> true); // returns all ids

在一般情况下,使在一个地方运行良好的代码在具有不同需求的其他地方运行良好是困难的,并且有理由重构它以适应新需求 - 并且有理由保持原样并简单地编写新代码。

请注意,如果您担心速度,使用流并不是一个好主意。例如,ids仅提取一次而不是两次可能会影响处理时间。对于非流代码,您可以将其保存在变量中。

例如,一次性代码通常比同时满足多个需求的代码更清晰、更快捷。尝试重构差异很大的代码库以共享更多内容可能会导致非常奇怪的设计,这些设计更难编码、调试和维护。见YAGNI


推荐阅读