2

I've been programming in Java for a while, but mainly just small command line programs. Now I've got an ever-so-slightly larger project, and I'm trying to work out a decent design. It's a small database lookup/update tool. I have three different types of tables, but there are several shared columns between the tables. EG:

Table1 (FieldName, FieldId, FieldValue, AppName, AppId, AppValue)
Table2 (FieldName, FieldId, FieldValue, UpdatedBy)
Table3 (FieldName, FieldId, FieldValue, UpdatedDate)

I want to have something like this:

abstract class BaseTable {
    FieldName
    FieldId
    FieldValue
}
class Table1 extends?implements? BaseTable {
    FieldName
    FieldId
    FieldValue
    AppName
    AppId
    AppValue
}
class Table2 extends?implements? BaseTable {
    FieldName
    FieldId
    FieldValue
    UpdatedBy
}
class Table3 extends?implements? BaseTable {
    FieldName
    FieldId
    FieldValue
    UpdatedDate
}

I'll read arguments to determine which type of table I need, but basically I want to do something like this:

BaseTable bt = null;
if (tableType = Table1)
    bt = new Table1();
else if (tableType = Table2)
    bt = new Table2();
else if (tableType = Table3)
    bt = new Table3();

bt.doSpecificStuff();
HashMap<String,BaseTable> map = new HashMap<String,Table1>();
map.put(someString, bt);

There are a couple of problems here:

  1. I can't access the subclass' extra fields using this design.

  2. I don't want to use Table1 t1 = new Table1();, because then I can't use common methods because of the different parameter types.

  3. When I try to create the hashmap to hold instances of the objects, I get a compile error saying:

    Type mismatch: cannot convert from HashMap<String,Table1> to HashMap<String,BaseTable>

So basically, there appear to be several problems with my design, and I can't think of an approach that solves these issues. I don't want to create three unrelated classes, because I feel that it defeats the purpose of OOO, and that my program warrants its use. Besides, this must be a common problem with a simple and elegant solution, but I haven't been able to find much that explicitly deals with an object having extra fields in its subclasses. Can anyone suggest a better design for my program, that somehow allows me to access the subclass fields while being able to instantiate with the base class object type?

blacktide
  • 10,654
  • 8
  • 33
  • 53
ftl25
  • 51
  • 1
  • 6
  • why don't you try `SomeTable implements Table1, Table2, Table3`. you can use object to this class to access any feilds in all tables. – maxx777 Apr 15 '14 at 22:03

2 Answers2

1

You should change the second to last line in your code to:

HashMap<String,BaseTable> map = new HashMap<String,BaseTable>();

Then you can put any instance of your subclasses into the map. From there, if you need to perform class-specific operations you can use the instanceof operator and cast your object:

if (bt instanceof Table1) {
    Table1 tmp = (Table1) bt;
    tmp.do_something();
}
else if (bt instanceof Table2) {
    Table2 tmp = (Table2) bt;
    tmp.do_something_else();
}

...

Hope this helps!

wickstopher
  • 981
  • 6
  • 18
1

There's nothing that says you cannot have different fields within subclasses. The problem you are encountering is a common design issue in which extending a class, while is seems logical, ends up making things more complicated.

From an OOP perspective I don't think your approach of using an abstract class for the BaseTable it that bad. Extending a class, as a general rule, only makes sense when the superclass and the subclass have an "is-a" relationship. In other words, when the subclass you are creating by extension really "is-a" version of the superclass. In your case this is true. Every table you create is some version of your abstract BaseTable.

The problem with extension, and I'm sure you realize this, is that changes in either the superclass or the subclass are not carried through in the other related instances. Changes in the BaseTable class will not be reflected in the subclasses you created. When you're dealing with 3 tables this is not such a big deal. If your database has 40 tables this can become a real pain.

That being said, the abstract class method is really your best option here. Using an interface would be incorrect because it would be assigning a type to all of your tables, i.e. everything would be considered a BaseTable, without a class hierarchy. The end result would probably work the same way but this is weird and confusing and should not be done because it makes your code harder to follow.

The HashMap issue is relatively easy to handle. With 3 separate classes you can use a heterogeneous container if you wanted to store each of the 3 tables in a custom collection. This way you can store instances of Table1, Table2 and Table3 without having to case everything to BaseTable and then use instanceof later.

Community
  • 1
  • 1
Rarw
  • 7,645
  • 3
  • 28
  • 46