Reputation: 9646
I've got two methods to extract data out of a CSV
private Car processCar (String [] row) {
Car c = new Car();
c.setCarId(Integer.parseInt(row[CSVColumns.carid.index]));
....
return c;
}
private Driver processDriver(String[] row) {
Driver d = new Driver(row[CSVColumns.name.index]);
sys.setAge(row[CSVColumns.age.index]);
...
return d;
}
Now, while extracting data out of the database I need to again make these two methods, however, with slight changes
private Car processCar (ResultSet rs) {
Car c = new Car();
c.setCarId(rs.getInt("Id"));
....
return c;
}
private Driver processDriver(ResultSet) {
Driver d = new Driver(rs.getString("Name));
sys.setAge(rs.getString("Age"));
.....
return d;
}
Is there a way to simplify this so that I don't have to repeat myself? Additionally, each method contains a lot of getters/setters so I would hate to copy paste stuff and make changes...
Upvotes: 3
Views: 112
Reputation: 340923
The idea is to have common adapter that translates either ResultSet
or CSV into something common behind consistent interface:
interface CarDataSource {
getCarId();
//...
}
And two implementations:
class CsvDataSource implements CarDataSource {
private final String[] row;
public CsvDataSource(String[] row) {
this.row = row;
}
public int getCarId() {
return Integer.parseInt(row[CSVColumns.carid.index]);
}
//...
}
class ResultSetDataSource implements CarDataSource {
private final ResultSet rs;
public ResultSetDataSource(ResultSet rs) {
this.rs = rs;
}
public int getCarId() {
return Integer.parseInt(rs.getString("Name));
}
//...
}
and this is how you use it:
private Car processCar(CarDataSource s) {
Car c = new Car();
c.setCarId(s.getCarId());
....
return c;
}
Providing either new CsvDataSource()
or new ResultSetDataSource()
.
Very similar approach, create and abstract factory:
interface CarFactory {
Car create();
}
With two implementations:
class CsvCarFactory implements CarFactory {
private final String[] row;
public CsvDataSource(String[] row) {
this.row = row;
}
public Car create() {
Car c = new Car();
c.setCarId(Integer.parseInt(row[CSVColumns.carid.index]));
//...
return c;
}
}
class ResultSetCarFactory implements CarDataSource {
private final ResultSet rs;
public ResultSetCarFactory(ResultSet rs) {
this.rs = rs;
}
public Car create() {
Car c = new Car();
c.setCarId(rs.getInt("Id"));
//...
return c;
}
//...
}
I don't like any of the approach above since they introduce a lot of boilerplate without adding much value. But the first approach is promising once you reduce it.
Have just one processCar()
that takes String[]
as an argument. However if you have a ResultSet
, simply translate it first to String[]
by extracting columns into subsequent items in arrays:
public String[] toStringArray(ResultSet rs)
The translation in the other direction so that ResultSet
is the base format is also possible, but ResultSet
is much harder to implement alone.
Upvotes: 1
Reputation: 2147
One solution could be to use an Adapter
interface.
interface ParamAdapter {
int getCarID();
//...
}
class ResultSetParamAdapter implements ParamAdapter {
private final ResultSet rs;
public ResultSetParamAdapter(ResultSet rs) {
this.rs = rs;
}
public int getCarID() {
return rs.getInt("Id");
}
//...
}
class StringArrayParamAdapter implements ParamAdapter {
private String[] array;
public ResultSetParamAdapter(String[] array) {
this.array = array;
}
public int getCarID() {
return Integer.parseInt(array[CSVColumns.carid.index]);
}
//...
}
The three dots are the other methods which you COULD need.
Upvotes: 0
Reputation: 323
One option is to write a method that takes a result set and converts to return a string array. Depending on your database library, this may be largely built in. So you create something like
String[] ResultSetToStrings(ResultSet aResultSet)
Then your call looks something like either
processCar(["1994","Ford","Probe","etc"]);
or
processCar(ResultSetToStrings(aResultSet));
and you discard the ResultSet versions of your code.
This may incur some efficiency penalty (probably negligble - time spent converting to CSV and some extra string manipulation). Also be sure to make sure your CSV comes out in the right order (may need to explicitly state column names and order in your SQL query and.or consult the CSVColumns object in your conversion routine) and handle things like multiple rows, blanks, commas in the field values, etc.
The reverse might also work - change your String[] into a result set. In fact, again depending on your database driver, this might be built in.
Upvotes: 1
Reputation: 104698
another approach which can simplify aspects of your program:
private Car processCar (String [] row) {
return new Car(Integer.parseInt(row[CSVColumns.carid.index]));
}
private Driver processDriver(String[] row) {
return new Driver(row[CSVColumns.name.index], row[CSVColumns.age.index]);
}
Although you would often make your life easier by using types more distinct than strings, then allow them to convert to and from string representations. Then your parser could support creating these specialized types from the CSV input. So adding type safety can also go a long way to remove redundancy and make it more maintainable.
Upvotes: 0