我认为这是一个很常见的问题,但我找不到任何可以帮助我的事情。我是一个相对较新的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程序员的任何建议?
提前致谢
感谢您的评论。让我回答这里的评论,为了清楚起见。
“为什么我要从子类隐藏这些方法(私有)?”为什么 你把车钥匙远离前门吗?
出于安全考虑,但为什么在更改colsFromLine
方法的访问修饰符时会影响安全性?此方法接受标头作为参数,因此它不依赖于任何内部状态也不会更改它。
我能想到的严格访问修饰符的下一个优点是帮助其他开发人员向他们展示他应该使用哪种方法以及逻辑所属的位置。
不要写你的测试依赖于内部实现 功能,只需编写一个测试来验证功能。
我没有。这取决于你对内部实现的意义。我不检查任何内部状态或变量。我只想测试将逐步解析CSV的算法。
“我的单元测试对这个类进行了如此多的测试” - 如果测试太多了 在课堂上,你应该重新考虑你的设计。这很可能是你的 从字面上看,这样做太多了,应该分手。
我的课上没有很多测试,但是当我按照我开始的方式进行测试时,我将为相同的方法(解析CSV)编写许多测试,因为它有许多边缘情况。由于不同的样板,测试的尺寸会增大。这就是我为什么要问这里的问题
答案 0 :(得分:3)
要回答您的直接问题:您始终努力从客户端代码中隐藏尽可能,但也要从子类中隐藏。
重点是:您希望(理论上)能够更改部分/全部实施,而不会影响系统中的其他元素。当客户端/子类代码知道这些实现细节时......迟早会有这样的代码开始依赖它们。为了避免这种情况,你要让它们远离视线。黄金法则是:良好的OO设计是关于对象和方法的行为(或“契约”)。你绝对不在乎如何某种方法可以完成它的工作;你只关心它的是什么。 如何部分应不可见!
话虽如此,有时为某些方法提供“包保护”可见性是有意义的;为了使它们在你的单元测试中可用。
除此之外:无论如何,我没有看到扩展你的CsvInput(更喜欢驼峰的情况,甚至是类名!)类。像往常一样:prefer composition over inheritance!
无论如何,这种“作业”是练习TDD的绝佳材料。你写了一个测试(检查一个方面);然后你编写代码来传递该测试。然后你写另一个测试检查“另一个”条件;等等。