I have a C++ program that connects to a database and retrieves some information. One of my function looks something like this. Please note this is a cut down version just to explain my logic or structure of the function.
void * MyDBClass::getDBData(const TableInfo& tInfo, const RelatedData& relData) const
{
//Initialise variables etc Common codevoid * retPtr = NULL;
....
....
if (tInfo.TableName == "TABLE_A")
{
//Do DB initialisation etc Common code
....
....
//Create empty Database table object and set its keys NOT Common code
TABLE_A* tableA;
tableA->Id = relData.Id;
//Retrieve Data from DB etc Common code
....
....
retPtr = static_cast<void *>(tableA);
}
elseif (tInfo.TableName == "TABLE_B")
{
//Do DB initialisation etc Common code
....
....
//Create empty Database table object and set its keys NOT Common code
TABLE_B* tableB;
tableB->Id = relData.Id;
tableB->Type = relData.Type;
//Retrieve Data from DB etc Common code
....
....
retPtr = static_cast<void *>(tableB);
}
// Clean up etc and then return
return retPtr;
}
From analyzing the above, the only point where my if-else body differs is the place where I set my actual tables key attributes (eg Id, Type).
I am looking to replace the if-else with some generic code (maybe Templates ???) so I can make the function Generic.
I can replace the tableA, tableB with T, but how can I set attributes generically. Is it even possible to do this sort of thing?
I take it that the user of this method has to cast to back to a TABLE_* to use the result. It should strike you that there's something very wrong here.
Is there a relationship between TABLE_A and TABLE_B?
I think you emphasis is wrong, forget templates and look at the object design. The pointers to specific TABLE types can be constructed using factories. But there's no point in attempting that unless you have a relationship between the things that can be returned where they can be treated in a general way.
Unfortunately I don't have access to the TABLE_* classes source code. They are provided by an external library.
There is no relationship between TABLE_A and TABLE_B.
So is if-else the only way out in such a scenario?
What library are you using? I would like to know why there are two disparate types TABLE_A and TABLE_B.
EDIT: You could always implement a wrapper class that manages the difference between TABLE_A and TABLE_B for you, but if you treat these types the same way I don't understand why they are different in the first place.
It is a external vendor supplied library. The two tables are quite distinct as they hold different aspects of data.
I can create a wrapper class that handles TABLE_A and TABLE_B, but still inside the class I will need to set Id for TABLE_A and Id and Type for TABLE_B. So will end up with a dependancy on the "Name" of the table and "Name of the attributes".
I am trying to avoid this dependancy if possible. In someways trying to do some sort of "Reflection" functionality as in c#.
If the two tables are distinct (i.e. there's no relationship), why are you trying to handle them together like this? It's not giving you anything, because when you're done, you still need to deal with that void*; I mean, you'll need to cast it to something (a TABLE_A or a TABLE_B) before you can use it.
Yes, if they hold different data, you shouldn't treat them the same. If they have a few common members, you can use duck-typing with templates, or you can represent the relationship by creating polymorphic wrapper classes, but really if they are different you shouldn't treat them the same. If whoever designed the library wasn't thinking too well, you just have to work around it.