Java 在我的情况下,避免使用幻数的最佳方法
我正在读取一个有许多列(22)的文件,我正在使用openCSV来读取该文件 每一行都表示为一个字符串数组Java 在我的情况下,避免使用幻数的最佳方法,java,architecture,Java,Architecture,我正在读取一个有许多列(22)的文件,我正在使用openCSV来读取该文件 每一行都表示为一个字符串数组nextLine[] 我必须处理/验证列,不想将它们称为数字(即nextLine[0]…nextLine[22]) 我更愿意将它们称为nextLine[COLUMN\u A]nextLine[COLUMN\u B]……等等。 我最初的方法是使用枚举创建一个单例 public enum Columns { INSTANCE; public int COLUMN_A = 0;
nextLine[]
我必须处理/验证列,不想将它们称为数字(即nextLine[0]
…nextLine[22]
)
我更愿意将它们称为nextLine[COLUMN\u A]nextLine[COLUMN\u B]……等等。
我最初的方法是使用枚举创建一个单例
public enum Columns {
INSTANCE;
public int COLUMN_A = 0;
....
public int COLUMN_X = 22;
}
然后我可以将该数组称为:
nextLine[Columns.INSTANCE.COLUMN_A]
问题
这是最好的方法吗?
我只是怀疑,因为我有另一个模型类,它只是为所有列提供了getter/setter,现在创建另一个类(singleton)以将列表示为索引似乎是一项额外的工作
对于上面的例子,如果我有一个模型类
public class Columns {
private String columnA;
public Columns (String columnA) {
this.columnA = columnA;
}
public void setColumnA(String columnA) {
this.columnA = columnA;
}
public String getColumnA() {
return this.columnA;
}
}
我可以使用
nextLine[columnA]
而不是创建单例枚举类吗?我建议使用HashMap
在您的例子中,可以是HashMap代码>
然后你可以得到你的价值观,比如:
String[] valuesIAmInterested = map.get(columnA);
更好的是,您可以真正使用对象列作为地图的键
HashMap<Column, String[]> map;
HashMap;
顺便说一句,enum不是单一模式。单一模式是一种特定的软件设计模式,enum传统上不这么认为。至少可以说,您对枚举的使用很奇怪。如果要使用枚举引用特定列,只需执行以下操作:
public enum Column {
public int index;
A(0), B(1), C(2), D(3);
public Column( int index ) {
this.index = index;
}
}
然后你就说:
String columnAValue = csv[row][Column.A.index]
这样做还允许您迭代所有列,如下所示:
for( Column column : Column.values ) {
String column = csv[row][column.index];
}
使用您使用的模式无法做到这一点,这使得使用枚举不值得。如果要继续执行您正在执行的操作,只需在文件顶部将它们设置为常规常量:
public class CsvParser {
public static final int COLUMN_A = 0;
public static final int COLUMN_B = 1;
public static final int COLUMN_C = 2;
}
这与您使用的枚举方法没有区别,只是更直接,不涉及定义另一个枚举
现在谈谈你的问题。这是最好的模式吗?以及它所依赖的所有架构类型问题。您是否正在构建一个必须对CSV的每一列进行特定验证的程序?可能列A是一个整数,必须用作整数,列B是一个字符串,列C是一个枚举,等等。或者,您必须将特定的逻辑附加到每一列,如果数据的格式始终是可预测的,则此模式是有意义的。如果您必须支持多种数据格式,但它们是固定的(即仅format1、format2、format3),那么您可以继续遵循此模式
但是,如果您必须读取任何类型的csv格式,但需要附加一些固定数量的解析和/或逻辑,那么您必须读入有关csv的一些元数据,以了解哪些列是数字、哪些是字符串等,并且可以通过查看元数据来附加您的逻辑。当然,这更为灵活,但定义元数据、读取元数据以及处理元数据并非易事。如果你不需要这个模型,就不要这样做。另一个模型工作量小得多,而且同样健壮
如果你从大局来看这件事。在第一个体系结构中,我们有元数据。这是我们在程序中创建的枚举或常量。因此,元数据被内置到程序中。在第二种样式中,我们将元数据从程序中移到外部表示中,这样就不会烘焙到程序中。用户可以在运行时更改元数据,而在第一个版本中,元数据是无法更改的。对于22列,我希望您不会单独处理这些列,而是以图解方式处理。因此,我将完全避免使用索引,并且
for (String columnElement : nextLine) {
// process columnElement
}
如果每一列都有单独的、特定的含义,那么数组(或列表或映射)也不是最好的设计。然后我宁愿使用枚举或类对每一行进行建模()。我不会为每一行编写(g,s)字母,而是使用多态性,以便枚举/类知道如何处理每一列。或者更好:为一行创建一个类,将处理委托给Column类型的对象,例如
class Line {
List<Column> columns;
public void processLine() {
for (Column c: columns) {
c.processColumn();
}
}
class Column {
public void processColumn() {
...
}
}
类行{
列出列;
public void processLine(){
用于(c列:列){
c、 processColumn();
}
}
类列{
public void processColumn(){
...
}
}
再想一想,我想这就是你可以做的:
public class CsvParser {
private File file;
private boolean hasHeader = false;
private Map<String,Integer> columnIndexes;
private List<String[]> rows = new ArrayList<String[]>();
public CsvParser( File file, boolean hasHeader ) throws IOException {
this.file = file;
this.hasHeader = hasHeader;
}
// use this to parse the header from the file
private void parseColumns(LineNumberReader reader) {
String line = reader.nextLine();
if( line != null ) {
String[] columns = line.split(",");
setColumns( columns );
}
}
// use this if there is no header in the data.
public void setColumns( String[] columns ) {
columnIndex = new HashMap<String,Integer>();
for( int i = 0; i < columns.length; i++ ) columnIndexes.put( columns.trim(), i);
}
public void parse() throws IOException {
LineNumberReader reader = new LineNumberReader( new FileReader( file ) );
try {
if( hasHeader ) parseColumns(reader);
while( (line = reader.nextLine()) != null ) {
rows.add( line.split(",") );
}
} finally {
reader.close();
}
}
public Collection<String> getColumns() {
return columnIndexes.keys();
}
public int size() {
return rows.size();
}
public int getInt( int row, String column ) {
return Integer.parseInt(getString(row,column));
}
public String getString( int row, String column ) {
return rows.get(row)[columnIndexes.get(column)];
}
public double getDouble( int row, String column ) {
return Double.parseDouble(getString(row,column));
}
public float getFloat( int row, String column ) {
return Float.parseFloat(getString(row,column));
}
}
公共类CsvParser{
私有文件;
私有布尔hasHeader=false;
私有地图索引;
私有列表行=新的ArrayList();
公共CsvParser(文件,布尔哈希头)引发IOException{
this.file=文件;
this.hasHeader=hasHeader;
}
//使用此命令可以解析文件的头
专用列(行号读取器){
String line=reader.nextLine();
如果(行!=null){
String[]columns=line.split(“,”);
设置列(列);
}
}
//如果数据中没有标题,则使用此选项。
公共void setColumns(字符串[]列){
columnIndex=newHashMap();
对于(inti=0;i