如何抽象这段代码,这样我就不会破坏DRY原则

时间:2012-10-31 20:06:02

标签: design-patterns architecture abstract

我有两种方法可以从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;
}

现在,在从数据库中提取数据时,我需要再次制作这两种方法,但需要稍作修改

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;
}

有没有办法简化这一点,以便我不必重复自己?另外,每种方法都包含很多getter / setter,所以我不想复制粘贴内容并进行更改......

4 个答案:

答案 0 :(得分:1)

一种选择是编写一个获取结果集并转换为返回字符串数组的方法。根据您的数据库库,这可能主要是内置的。所以你创建类似

的东西
String[] ResultSetToStrings(ResultSet aResultSet)

然后你的电话看起来像是

processCar(["1994","Ford","Probe","etc"]);

processCar(ResultSetToStrings(aResultSet));

并丢弃代码的ResultSet版本。

这可能会导致一些效率损失(可能是可忽略的 - 转换为CSV的时间和一些额外的字符串操作)。另外一定要确保你的CSV按照正确的顺序出现(可能需要在SQL查询中明确说明列名和顺序,或者在转换例程中查询CSVColumns对象)并处理多行,空格,逗号等内容在字段值等

反向也可能有效 - 将String []更改为结果集。实际上,同样取决于您的数据库驱动程序,这可能是内置的。

答案 1 :(得分:1)

抽象数据源并使用通用接口

我们的想法是使用通用适配器将ResultSet或CSV转换为一致界面背后的常见内容:

interface CarDataSource {

    getCarId();
    //...

}

两个实现:

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));
    }

    //...

}

这就是你如何使用它:

private Car processCar(CarDataSource s) {
    Car c = new Car();
    c.setCarId(s.getCarId());
    ....
    return c;
}

提供new CsvDataSource()new ResultSetDataSource()

抽象工厂有两个实现:

非常相似的方法,创建和抽象工厂:

interface CarFactory {

    Car create();

}

有两个实现:

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;
    }

    //...

}

组合

我不喜欢上面的任何方法,因为它们引入了很多样板而没有增加太多价值。但是一旦你减少它,第一种方法就很有希望。

只有一个processCar()String[]为参数。但是,如果您有ResultSet,只需将列提取到String[],然后将列提取到数组中的后续项目中:

public String[] toStringArray(ResultSet rs)

另一个方向的翻译也可以ResultSet是基本格式,但ResultSet更难单独实施。

答案 2 :(得分:0)

另一种可以简化程序方面的方法:

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]);
}

虽然您通常会使用比字符串更明显的类型来让您的生活更轻松,但允许它们与字符串表示形式进行转换。然后,您的解析器可以支持从CSV输入创建这些专用类型。因此,添加类型安全性也可以很长时间地消除冗余并使其更易于维护。

答案 3 :(得分:0)

一种解决方案可能是使用Adapter接口。


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]);
    }

    //...
}

这三个点是您可能需要的其他方法。