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

标签 java unit-testing junit tdd software-design

我认为这是一个很常见的问题,但我找不到任何对我有帮助的东西。我对java比较陌生,正在为工作申请而锻炼。为此,我开始编写一个转换数据的工具。 (例如,读取 CSV、翻译一些列并将其作为 SQL 插入文件写入)

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

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

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 方法会变得更加复杂。我对这个类的单元测试已经测试了很多,我真的不想在开发时脑子里有太多东西。

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

提前致谢

<小时/>

回复评论

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

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

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

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

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)编写许多测试,因为它有很多边缘情况。由于样板不同,测试的规模将会增大。这就是我在这里问的原因

最佳答案

回答你的直接问题:你总是努力尽可能多地隐藏来自客户端代码以及子类。

要点是:您希望(理论上)能够更改部分/全部实现,而不影响系统中的其他元素。当客户端/子类代码知道此类实现细节时......迟早,此类代码开始依赖它们。为了避免这种情况,你要把它们放在看不见的地方。黄金法则是:好的 OO 设计是关于对象和方法的行为(或“契约”)。您绝对不关心某些方法如何完成其工作;您只关心它做什么如何部分应该不可见!

话虽如此,有时为某些方法提供“受包保护”的可见性确实有意义;以便使它们在您的单元测试中可用。

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

无论如何,这样的“作业”都是极好的练习素材TDD 。您编写一个测试(检查一个方面);然后编写代码来通过该测试。然后你编写另一个测试来检查“另一个”条件;等等。

关于java - 我应该在 java 中的方法中使用哪个访问修饰符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41968582/

相关文章:

java - 是否可以修改一个非 volatile 变量,使另一个线程能够 "see"更新?

java - 在创建 XMLGregorianCalendar 时使用 DataTypeFactory 严重影响性能

java - Java 中的额外导入会减慢代码加载时间吗?

java - Camunda测试部署注释未部署

java - JUnit 测试 SQL 查询

java - 你知道有一个Java库可以访问原生linux api吗?

c++ - 如何启用使用另一个类的静态方法的模板函数的自动推导,从而消除冗长的调用者代码

java - Lombok 注释与 Cobertura 或类似工具中的代码覆盖率

ios - XCode 9 缺少 CoreSimulator.framework

build - Gradle里程碑4/5在具有插件实例化异常的测试中失败