我应该为 java 中的方法使用哪个访问修饰符?

Which access modifier should I use for my methods in java?

我认为这是一个很常见的问题,但我找不到任何可以帮助我的问题。我是 java 的新手,正在为一份工作申请做准备。为此,我开始编写一个工具来转换数据。 (例如,读取 CSV,翻译一些列并将其作为 SQL 插入文件写入)

如果您有兴趣可以在这里找到它,我会复制一些代码来解决我的问题:https://github.com/fvosberg/datatransformer

我从 Class 开始,它应该读取 CSV(并且通过包含一些应该包含分隔符等的字段会变得更加复杂)。我的 IDE (IntellJ IDEA) 建议尽可能对我的方法使用严格的访问修饰符。为什么我应该对 subclasses 隐藏这些方法(使用私有方法)?

package de.frederikvosberg.datatransformer;

import java.io.BufferedReader;
import java.io.Reader;
import java.util.*;

class CSVInput {
    private final BufferedReader _reader;
    private String separator = ",";

    public CSVInput(Reader reader) {
        _reader = new BufferedReader(reader);
    }

    public List<SortedMap<String, String>> readAll() throws java.io.IOException {
        List<SortedMap<String, String>> result = new LinkedList<>();
        List<String> headers = readHeaders();

        String line;
        while ((line = _reader.readLine()) != null) {
            result.add(
                    colsFromLine(headers, line)
            );
        }
        _reader.close();
        return result;
    }

    private List<String> readHeaders() throws java.io.IOException {
        List<String> headers = new ArrayList<>();

        String line = _reader.readLine();
        if (line == null) {
            throw new RuntimeException("There is no first line for the headers in the CSV");
        }

        return valuesFromLine(line);
    }

    public void setSeparator(String separator) {
        this.separator = separator;
    }

    /**
     * creates a list of values from a CSV line
     * it uses the separator field
     *
     * @param line a line with values separated by this.separator
     * @return a list of values
     */
    private List<String> valuesFromLine(String line) {
        return Arrays.asList(
                line.split(this.separator)
        );
    }

    private SortedMap<String, String> colsFromLine(List<String> headers, String line) {
        SortedMap<String, String> cols = new TreeMap<>();
        List<String> values = valuesFromLine(line);
        Iterator<String> headersIterator = headers.iterator();
        Iterator<String> valuesIterator = values.iterator();
        while (headersIterator.hasNext() && valuesIterator.hasNext()) {
            cols.put(headersIterator.next(), valuesIterator.next());
        }
        if (headersIterator.hasNext() || valuesIterator.hasNext()) {
            throw new RuntimeException("The size of a row doesn't fit with the size of the headers");
        }
        return cols;
    }
}

另一个缺点是单元测试。我想为我的方法编写单独的测试。特别是 CSVInput::valuesFromLine 方法会变得更加复杂。我对此 class 的单元测试测试了很多,我真的不想在开发时脑子里有很多东西。

有经验的 Java 程序员有什么建议吗?

提前致谢


回复评论

感谢您的评论。为了清楚起见,让我在这里回答评论。

"Why should I hide these methods (with private) from subclasses?" Why do you keep your car keys away from your front door?

出于安全考虑,但是为什么我更改colsFromLine方法的访问修饰符会影响安全?此方法接受 headers 作为参数,因此它不依赖于任何内部状态,也不更改它。

我能想到的严格访问修饰符的下一个优点是帮助其他开发人员向他们展示他应该使用哪个方法以及逻辑属于哪里。

Don't write your test to depend on the internal implementation of the functionality, just write a test to verify the functionality.

我不知道。这取决于您对内部实施的含义。我不检查任何内部状态或变量。我只想测试将逐步解析 CSV 的算法。

"My Unit test for this class is testing so much" - If too many tests on a class, you should rethink your design. It's very likely that your class literally is doing too much, and should be broken up.

我的 class 上没有很多测试,但是当我按照开始的方式进行时,我将为相同的方法(解析 CSV)编写很多测试,因为它有很多边缘情况。由于样板文件不同,测试的规模会增加。这就是我为什么要在这里问的问题

回答你的直接问题:你总是努力从任一客户端代码中尽可能地隐藏,但也从子classes中隐藏。

重点是:您希望(理论上)能够 更改 parts/all 您的实施而不影响系统中的其他元素。当 client/subclass 代码知道此类实现细节时...迟早,此类代码会开始依赖它们。为避免这种情况,请将它们放在视线之外。黄金法则是:良好的 OO 设计是关于对象和方法的 行为 (或 "contracts")。您绝对不关心如何某种方法发挥作用;您只关心它的 是什么 how 部分应该 invisible!

话虽如此,有时让 "package protected" 可见您的某些方法确实有意义;为了使它们在您的单元测试中可用。

除此之外:我认为扩展 CsvInput 没有多大意义(更喜欢驼峰式大小写,即使是 class 名称!)无论如何 class。像往常一样:prefer composition over inheritance!

不管怎么说,这样的"assignments"对于练习TDD来说是极好的material。您编写一个测试(检查 one 方面);然后您编写代码以通过该测试。然后你写 另一个 测试检查 "another" 条件;等等。