views:

68

answers:

2

I'm having some problems with using generics in combination with parallel class hierarchies. I have coded myself into this mess several times already.

Let's say I have the following class hierarchies: TableColumn -> subclasses SqlTableColumn, OracleTableColumn Table -> subclasses SqlTable, OracleTable Database -> subsclasses SqlDatabase, OracleDatabase

I use generics on the base types, which gives:

Table<TableColumn>
Database<Table<TableColumn>>

SqlTable<SqlTableColumn>
SqlDatabase<SqlTable<SqlTableColumn>>

OracleTable<OracleTableColumn>
OracleDatabase<OracleTable<OracleTableColumn>>

I have a feeling this is not a good use of generics. What would be a better design?

+1  A: 

Generics (as in Java or C#) is really intended to support parameterized types. In this case, the types you are passing (TableColumn, SqlTableColumn) are not really intended to be type parameters.

I would implement this set of types as parallel object hierarchies, not parameterized types. For example:

OracleTable extends Table
SqlTable extends Table

OracleDatabase extends Database
SqlDatabase extends Database

OracleTableColumn extends TableColumn
SqlTableColumn extends TableColumn

The public methods on all these types should refer only to the base classes, as is done in JDBC, for example.

Avi
+2  A: 

Ignoring any theoretical stuff behind generics on when to use them, this seems more natural to me (in C#):

class Database<T, C>
    where T : Table<C>
    where C : TableColumn { }
class Table<C>
    where C : TableColumn { }
class TableColumn { }

//sql
class SqlDatabase : Database<SqlTable, SqlColumn> { }
class SqlTable : Table<SqlColumn> { }
class SqlColumn : TableColumn { }

//oracle
class OracleDatabase : Database<OracleTable, OracleColumn> { }
class OracleTable : Table<OracleColumn> { }
class OracleColumn : TableColumn { }
Bubblewrap