【问题标题】:Which access modifier should I use for my methods in java?我应该为 java 中的方法使用哪个访问修饰符?
【发布时间】:2017-01-31 22:24:18
【问题描述】:

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

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

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

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 程序员有什么建议吗?

提前致谢


回复 cmets

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

“我为什么要从子类中隐藏这些方法(私有)?”为什么 您是否将车钥匙远离前门?

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

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

不要将测试编写为依赖于 功能,只需编写一个测试来验证功能。

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

“我对这个类的单元测试测试太多了” - 如果测试太多 在课堂上,你应该重新考虑你的设计。很有可能你的 类字面上做的太多了,应该分解。

我的课堂上没有太多测试,但是当我按照我开始的方式进行时,我将为同一个方法(解析 CSV)编写许多测试,因为它有很多边缘情况。由于不同的样板,测试的规模会增加。这就是我在这里问的原因

【问题讨论】:

  • “我为什么要从子类中隐藏这些方法(私有)?”为什么你的车钥匙远离你的前门?
  • 不要编写测试依赖于功能的内部实现,只需编写测试来验证功能。如果您稍后决定更改您的实现,您的测试应该能够告诉您新的实现仍然产生正确的结果。如果您正在测试您的实现,那么这将不起作用。
  • “我的这个类的单元测试测试太多了” - 如果一个类的测试太多,你应该重新考虑你的设计。很可能您的班级确实做得太多,应该被打散。
  • 谢谢,这很快;-)

标签: java unit-testing junit tdd software-design


【解决方案1】:

回答您的直接问题:您总是努力对任一客户端代码以及子类隐藏尽可能

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

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

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

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

【讨论】:

  • 非常感谢您的回答,这对我帮助很大,因为我没有想到“可以改变什么”部分。扩展我的意思是扩展方法本身,而不是带有子类的类。因为诸如封闭字段中的换行符之类的边缘情况等等。我必须更多地考虑这个案子,我将在晚上发表评论。谢谢!
  • 不客气。我更新了我的回答,提到这些问题对于使用 TDD 来说是完美的
  • 谢谢。我正在用这个项目练习 TDD。这就是为什么我想要从外部访问 colsFromLine 方法的原因。仅自行测试此方法。
猜你喜欢
  • 2016-05-17
  • 2019-08-15
  • 2018-04-18
  • 2021-09-18
  • 1970-01-01
  • 2014-09-08
  • 2013-05-25
  • 2015-11-27
  • 2012-03-08
相关资源
最近更新 更多