Re: Application design question....
"MF" <mojtaba_danai@yahoo.com> wrote in message
news:1153693343.557039.68350@p79g2000cwp.googlegroups.com...
Hi Frederic
Thanks for the answer. I have couple of questions for clearance.
- It must be possible to run all adapters at the same time, and if one
of the data sources fails then a new data source wih a new adapter
shall take in place.
Exactly. The DataSourceHandler keeps a list of all data sources (adapters
are classes, the data sources are implementations of the different
adapters). You can program any rule you want to choose from which of this
data source it will get its data, for example, keep in a variable a pointer
to the latest data source used, which will be re-used as long as it is
working, and if it fails, try the other one in sequence till one succeeds or
all failed.
class DataSourceHandler : public DataSourceInterface
{
private:
// List of all data sources
std::list<DataSourceInterface*> datasources;
// Latest tried data source is an iterator into the list
std::list<DataSourceInterface*>::iterator current;
public:
// implementation of fetchData for DataSourceHandler
virtual int fetchData(CommonData& data);
};
int DataSourceHandler::fetchData(CommonData& data)
{
std::list<DataSourceInterface*>::iterator = last;
int errorCode = 1;
do {
errorCode = (*current)->fetchData(&data);
if (errorCode == 0)
{
// success
return errorCode;
}
++current;
if (current == datasource.end())
{
// last data source in the list, go to the beginning of the list
current = datasource.begin();
}
} while (current != last);
// All data sources have failed
return errorCode;
}
- How are the factories designed? You had mentioned with objects with
virtual functions, can you give a sketch?
- Why ths factories are necessary? Is it possible to do without
factory? What is implication if do without them?
Factories are not necessary. You can use the simple mean of using chained
if/then/else to select the adapter for a data source:
while (!endOfConfiguration())
{
AdapterConfigInfo config = getNextAdpaterConfig()
std::string adapterName = config.getAdapterName();
DataSourceInterface datasource;
if (adpatorName == "AdapterA")
{
datasource = new AdapterA(config.getLocationA(), ...);
}
else if (adaptorName == "AdaptorB")
{
datasource = new AdapterB(config.getHostB(), getUserB(), ...);
}
else if (...)
{
...
}
else
{
// unknown adaptor name
return error;
}
datasources.add(datasource);
}
This can become complex if you have a lot of Adaptors (not datasources,
Adaptors, which are types of datasources). So you can use instead a map to
associate names with a pointer to function to build new data source:
DataSourceInterface* createAdapterADataSource(ConfigData& config)
{
return new AdapterA(config.getLocationA(), ...);
}
DataSourceInterface* createAdapterBDataSource(ConfigData& config)
{
return new AdapterA(config.getHostB(), getUserB(), ...);
}
....
typedef DataSourceInterface builderFunction(ConfigData& config);
std::map<std::string, builderFuntion*> builders;
builders["AdpaterA"] = &createAdapterA;
builders["AdpaterB"] = &createAdapterB;
builders["AdpaterC"] = &createAdapterC;
....
while (!endOfConfiguration())
{
AdapterConfigInfo config = getNextAdpaterConfig()
builderFunction* builder = builders[config.getAdaptername()];
DataSourceInterface datasource = (*builder)(config);
datasources.add(datasource);
}
This allow full separation of code for each Adapter in its own module.
Factories is a step further in generalization:
class AdaptorFactory
{
virtual DataSourceInterface* create(ConfigData& config) = 0;
};
class AdaptorAFactory : public AdaptorFactory
{
DataSourceInterface* create(ConfigData& config)
{
return new AdaptorA(config.getLocationA(), ...);
}
};
std::map<std::string, AdaptorFactory*> factories;
factories["AdpaterA"] = new AdaptorAFactory();
factories["AdpaterB"] = new AdaptorBFactory();
....
while (!endOfConfiguration())
{
AdapterConfigInfo config = getNextAdpaterConfig()
DataSourceInterface datasource =
factories[config.getAdaptername()]->create(config);
datasources.add(datasource);
}
Factories is not only used to avoid pointer syntax, they can have more
functionalities: several create() functions to get configuration from
different sources, life cycle management (initializations and finalizations)
and framework to help registering the factories in the map.
- Are both Adapter and DataSourceHandler implementation of
DataSourceInterface?
This is not necessary. But it is easy to see that they can be seen as having
the same interface and semantic: the datasource handler is meant to fetch
and convert the data to the application. The only difference is that the
DataSourceHandler uses other data sources to do its job and does not need to
convert the data (its internal data sources have already done it).
--
Fr?d?ric Lachasse - ECP86
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]