I am new to programming and encounter a question that need your experience:
I have a list of data. Each data has a format.
I have a class Builder which scan the data list and build a data tree according to their format.
As far as I can figure out, there are two ways to accomplish this:
1. Bind each data with an int/enum value to describe what it is, and the Builder can examine the int/enum value to decide which function should be used to handle token.
2. Bind each data with an virtual function which implements an interface, and call the virtual function to handle the data.
It sounds like the 2nd method is better. However, I also encounter some issues with it:
1. Is it okay to embedded the code to handle data into a data? If someday I need to modify the Builder class, I may have to modify each data class?
2. In some scenarios I need two data to cooperator together, it is hard to do this in method 2.
Could you kindly guide me which one is better?
Here are some example code:
Method 1:
struct FormatedData
{
std::string data;
int format;
};
class Builder
{
public:
void build(std::list<FormatedData> *data_list)
{
for (auto it : *data_list)
{
switch (it.format)
{
case:
do something;
break;
default:
do something;
break;
}
}
}
};
Method 2:
class Builder;
struct IIterface
{
virtual void dosomething(Builder*) = 0;
};
class FormatedData :public IIterface
{
std::string data;
int format;
void dosomething(Builder*) override
{
....
}
};
class Builder
{
public:
void build(std::list<IIterface*> *data_list)
{
for (auto it : *data_list)
{
it->dosomething(this);
}
}
};
Method 2 is better. Some comments:
1) all behavior for handling the data should be encapsulated in a class for handling the data. there should be no conditional statements which depend on types of data in the managing classes.
2) use factory pattern for creating new objects without changing the previously defined classes:
Related
We are using a PubSub framework that uses template methods to register topics and identify as a publisher or subscriber. For example, to register a topic name in the system you'd call:
RegisterTopic<T>(std::string topicName);
I would like to be able to create a parameter list (or configuration list if you will) to identify the needed registration topics in use by a given application configuration using a simple struct like
struct RegistrationTopicType
{
std::string name;
int type; // replace with some mechanism to store a data type
};
However I haven't found a working mechanism to replace the int in the struct above with something to store a data type.
I'm trying to do this so that I can maintain a list of topics and their types in the system:
std::vector<RegistrationTopicType> topicList = {
{"topic1", MyClass},
{"topic2", MyOtherClass}, // and on and on.
};
which I could use later do things like call the templated Registration method.
for (auto & topic : topicList) {
RegisterTopic<topic.type>(topic.name);
}
I have experimented with templated struct where I tried to store the data type such as
template<typename T>
struct TemplatedRegistrationTopic
{
using DataType = T;
std::string name;
};
But while I can implement instances of this struct,
TemplatedRegistrationTopic <float> topic{"floatTopic"};
TemplatedRegistrationTopic <MyClass> topic{"MyClassTopic"};
I can't seem to access the "DataType" variable as a datatype to use in the Registration method.
RegisterTopic<topic.DataType>(topic.name); // this fails.
I saw somewhere to use '::' but that also fails:
Register<topic::DataType>(topic.name); // this also fails.
Problems of storing a bunch of topics of different types in a common list aside, is what I'm trying to do (store a data type for later use in a templated method) even possible?
In the ol' days I might have created an enum list with an enum for of the possible types and then used that to select the actual type in a massive switch statement, but I don't want to have to maintain a mapping between all of the possible types and an enum in a giant switch statement which seems to defeat the purpose of using templates. eg I don't want to end up with this, but its effectively what I'm trying to do:
enum typelist { Type1, Type2 }; // one for each type that might be used as a topic
struct EnumRegistrationTopicType
{
std::string name;
typelist type;
};
std::vector<EnumRegistrationTopicType> enumTopicList = {
{"topic1", Type1},
{"topic2", Type2}, // and on and on.
};
for (auto & topic : enumTopicList) {
switch (topic.type) {
case typelist::Type1:
RegisterTopic<MyClass1>(topic.name);
break;
case typelist::Type2:
RegisterTopic<MyClass2>(topic.name);
break;
}
}
Let's do a classic OO design.
struct RegistratorBase {
virtual ~RegistratorBase() = default;
virtual void doRegistration(const std::string& topic) const = 0;
};
template <typename T>
struct Registrator {
void registerTopic(const std::string& topic) const override {
doRegistration<MyClass1>(topic);
}
};
struct RegistrationTopicType {
std::string name;
std::unique_ptr<RegistratorBase> registrator;
}
Now you can add these things to a vector
std::vector<RegistrationTopicType> topicList {
{ "topic1", new Registrator<MyClass1> },
{ "topic2", new Registrator<MyClass2> },
};
and register everything
for (const auto& topic: topicList) {
topic.registrator->doRegistration(topic.name);
}
Of course now one starts to wonder, why is RegistrationTopicType needed at all? Why not shove the name directly to the Registrator? OK let's try:
struct RegistratorBase {
virtual ~RegistratorBase() = default;
// no need for other virtual members
};
template <typename T>
struct Registrator {
Registrator (const string& topic) {
RegisteerTopic<T>(topic);
}
};
Nice! Now let's put this into a vector:
std::vector<std::unique_ptr<RegistratorBase>> topicList {
new Registrator<MyClass1>("topic1"),
new Registrator<MyClass2>("topic2")
};
Great! But why do we need a vector of these things? We construct the vector of registrators and never use it anymore. Why not just create a bunch of variables instead?
Registrator<MyClass1> r1("topic1");
Registrator<MyClass2> r2("topic2");
But that's not really different from a list of function calls:
RegisterTopic<MyClass1>("topic1");
RegisterTopic<MyClass2>("topic2");
So variables are not needed either, nor are their classes. Put the calls somewhere and you are done. They are your configuration list.
We have successfully designed, simplified, and finally eliminated a totally redundant software component!
Perhaps some of the simplification steps will not be applicable to your case, in which case the component will not be redundant for you. But I have no way of knowing that.
I'm currently working with a System/Data hierarchy implemented like this:
class SystemData
{
}
class SystemDataA : public SystemData
{
int x;
}
class SystemDataB : public SystemData
{
float y;
}
class System
{
virtual SystemData* getData() = 0;
virtual Result computeData(SystemData*) = 0;
}
class SystemA : public System
{
// really returns SystemDataA
SystemData* getData() override;
Result computeData(SystemData*) override;
}
class SystemB : public System
{
// really returns SystemDataB
SystemData* getData() override;
Result computeData(SystemData*) override;
}
In the end there is a controller class which does sth similar to this:
void foo()
{
for(auto& s : systemVec)
{
SystemData* data = s->getData();
FinalResult final = s->computeData(data);
}
}
Whereas now each specific system dynamic_casts back to the concrete type it is able to process. This seems like pretty bad design and I'd like to refactor this into sth more reasonable. My first idea was to just implement the computation algorithm inside the SystemData classes and then just do:
SystemData* data = s->getData();
FinalResult final = data->compute();
but does it really belong there?
It appears more intuitive to have a separate algorithm hierarchy, probably implemented with the strategy pattern. However then I again have the problem of losing runtime type info of the data because all algorithms get passed the abstract data type and in the end will have to dynamic cast and do nullptr and error checks again. So is it still better to implement the algorithm inside the data classes itself? Can I maybe still implement the hierarchy in a separate module and just add function pointers or a similar construct to the data class? Is there a completely different solution I'm not aware of?
I have the following C++ design problem.
Suppose I have the following class:
class Model {
Model(int numberOfModels, int flag=-1) :
_models(numberOfModels), _flag(flag){ }
void buildModel(){
for (int id=0; id<_models.size(); ++id) {
if (flag == -1){
BuilderOne builder;
builder.build(&_models[id]);
}
else {
BuilderTwo builder;
builder.build(&_models[id]);
}
}
}
private:
vector<SimpleModel> _models;
int _flag;
};
where the member function "buildModel" builds a vector of "SimpleModel" object. "BuilderOne" and "BuilderTwo" are different builder class which all implements a "build" method (or they can be inherited from the same BaseBuilder class using CRTP).
But the above implementation is quite cumbersome, since the type of builder should be predetermined by "_flag" before entering the loop. What I really want is the following implementation of "buildModel" method:
void buildModel(){
if (flag == -1){
BuilderOne builder;
else
BuilderTwo builder;
for (int id=0; id<_models.size(); ++id)
builder.build(&_models[id]);
}
However, the above code doesn't compile because 1) object "builder" is not visible after the if statement 2) type of the "builder" cannot be decided at compile time.
The above functionality can easily be realized by making the "build" method a virtual function in a BaseBuilder. But virtually function is not considered as a solution because of various reasons in our library. But inheritance (like CRTP) would be acceptable.
Some one could help to get around with this problem?
With the [insane] requirement that virtual functions cannot be used your current implementation is just broken. Every time a new builder type is added you will have to update your Model class. This may be exactly what you want (your post is unclear on this) so I'll try to cover both approaches with a single solution.
First you can start by taking advantage of static polymorphism and place the main functionality in a function template. This will help you get around the lack of virtual functions in reducing the amount of code necessary to use it.
class Model
{
public:
template<class BuilderType>
BuilderType buildModel()
{
BuilderType builder;
// Perform other tasks here
for (int id = 0; id<_models.size(); ++id)
{
builder.build(&_models[id]);
}
// Perform other tasks here
return builder;
}
};
This will allow you to use object type as long as it implements a build function that takes a pointer to an instance of SimpleModel. You also have the option of taking a builder as an argument to the function which will allow automatic type deduction. Whether you make it public, private, or protected is up to you and how you decide to move forward. This may be all that you need but if you want to limit the buildModel function to a specific set of builders you can make it protected or private and provide a public function that simplifies the building process.
class Model
{
public:
void buildModel()
{
switch (flag_)
{
case -1:
buildModelByType<BuilderOne>(b);
break;
default:
buildModelByType<BuilderTwo>(b);
break;
}
}
protected:
template<class BuilderType>
BuilderType buildModelByType()
{
BuilderType builder;
// Perform other tasks here
for (int id = 0; id<_models.size(); ++id)
{
builder.build(&_models[id]);
}
// Perform other tasks here
return builder;
}
};
Whether you take the builders by argument or return the result of the building process is up to you. Your post wasn't specific about that aspect of the problem but this should be easily adaptable to whatever you're towards.
I have a very complicated code structure, but the important bits are:
typical setup: I have a base class and two classes that derive from this base class and each has own members, and which don't have a standard constructor
class BaseSolver{
...
};
class SolverA : BaseSolver{
public:
std::string a;
SolverA(TypeA objectA);
};
class SolverB : BaseSolver{
public:
int b;
SolverB(TypeB objectB);
};
Now I have a config xml file from which I read whether I have to use SolverA or SolverB. Therefore I have an IOService:
template<class T>
class IOService
{
BaseSolver* getSolver()
{
std::string variableThatIReadFromXML;
/* here I have to perform many actions before I can create a solver object
* to retrieve the data needed for the constructors */
TypeA variableIConstrucedWithDataFromXML;
TypeB anotherVariableIConstrucedWithDataFromXML;
if (variableThatIReadFromXML == "a")
return new SolverA(variableIConstrucedWithDataFromXML); // I know that this can leak memory
else if (variableThatIReadFromXML == "b")
return new SolverB(anotherVariableIConstrucedWithDataFromXML);
}
};
And somewhere in my application (for simplicity let's say it's the main.cpp):
int main(){
IOService ioService;
BaseSolver* mySolver = ioService.getSolver();
}
That is absolutely fine.
But now, in the main I have to access the members of the derived classes a and b respectively.
How can I do this?
I thought of retreving only the type of the Solver from the IOService:
class IOService
{
decltype getSolverType()
{
std::string variableThatIReadFromXML;
/* here I have to perform many actions before I can create a solver object
* to retrieve the data needed for the constructors */
TypeA variableIConstrucedWithDataFromXML;
TypeB anotherVariableIConstrucedWithDataFromXML;
if (variableThatIReadFromXML == "a")
return new SolverA(variableIConstrucedWithDataFromXML); // I know that this can leak memory
else if (variableThatIReadFromXML == "b")
return new SolverB(anotherVariableIConstrucedWithDataFromXML);
}
TypeA getConstructorDataForSolverA()
{
/* here I have to perform many actions before I can create a solver object
* to retrieve the data needed for the constructors */
return variableIConstrucedWithDataFromXML;
}
TypeB getConstructorDataForSolverB()
{
/* here I have to perform many actions before I can create a solver object
* to retrieve the data needed for the constructors */
return anotherVariableIConstrucedWithDataFromXML;
}
};
But of course I can't specify decltype as return value.
I'm really helpless. I would appreciate any hint into the right direction, or even a solution for this problem.
[Edit]: The derived solver classes need more than only the information from the xml file to work properly. That means, that I have to set some more properties which come from a mesh file. So I could give the meshfile to the IOService, so that the IOService could set the appropriate members this way:
class IOService
{
BaseSolver* getSolver(MeshType myMesh)
{
std::string variableThatIReadFromXML;
/* here I have to perform many actions before I can create a solver object
* to retrieve the data needed for the constructors */
TypeA variableIConstrucedWithDataFromXML;
TypeB anotherVariableIConstrucedWithDataFromXML;
if (variableThatIReadFromXML == "a")
{
auto solverA = new SolverA(variableIConstrucedWithDataFromXML); // I know that this can leak memory
solverA.a = mesh.a;
}
else if (variableThatIReadFromXML == "b")
{
auto solverB = new SolverB(anotherVariableIConstrucedWithDataFromXML);
solverB.b = mesh.b;
}
}
};
But then the IOService needs to know the class MeshType, what I want to avoid, because I think that it breaks encapsulation.
So I wanted to set the member a and b, respectively, in another part of my program (here for simplicity in the main).
Taking this into account, only the answer from Daniel Daranas seems like a solution for me. But I wanted to avoid dynamic casts.
So a reformulated question could be: How should I change my design to ensure encapsulation and avoid dynamic casts? [/Edit]
I am using clang 3.4 ob ubuntu 12.04 lts.
Use dynamic_cast to try to cast a pointer-to-base-class to pointer-to-derived-class. It will return NULL if the pointed-to object of the base class does not exist (NULL value of the base pointer), or is not actually a derived class object. If the result, instead, is not NULL, you have a valid pointer-to-derived-class.
int main(){
IOService ioService;
BaseSolver* mySolver = ioService.getSolver();
SolverB* bSolver = dynamic_cast<SolverB*>(mySolver);
if (bSolver != NULL)
{
int finallyIGotB = bSolver->b;
cout << finallyIGotB;
}
}
Note that there may be some better design solutions than using dynamic_cast. But at least this is one possibility.
The funny thing about polymorphism is that it points out to you when you are not using it.
Inheriting a base class in the way you are serves 1 purpose: to expose a uniform interface for objects with different behaviors. Basically, you want the child classes to look the same. If I have classes B and C that inherit from A, I want to say "do foo" to the class, and it'll do foob or fooc.
Essentially, you're flipping it around: I have a B and C of type A, and if it is B i want to do foob and if it is C I want to do fooc. While this may seem scary, usually the best way to solve the problem is to rephrase the question.
So to your example, you are currently saying "OK, so I have an XML file, and I will read data from it one way if I'm making an A, or another way if I'm making a B." But the polymorphic way would be "I have an XML file. It tells me to make an A or a B, and then I tell the instance to parse the XML file".
So one of the ways to solve this to change your solver interface:
class BaseSolver
{
public:
virtual void ReadXMLFile(string xml) = 0;
...
};
While this does rephrase the problem in a way that uses polymorphism, and removes the need for you to see what you've created, you probably don't like that for the same reason I don't: you'd have to supply a default constructor, which leaves the class in an unknown state.
So rather than enforce it at the interface level, you could enforce it at the constructor level, and make both SolverA and SolverB have to take in the XML string as part of the constructor.
But what if the XML string is bad? Then you'd get an error state in the constructor, which is also a no-no. So I'd deal with this using the factory pattern:
class SolverFactory;
class BaseSolver
{
public:
virtual void solve() = 0;
protected:
virtual int ReadXML(std::string xml) = 0;
friend class SolverFactory;
};
class A : public BaseSolver
{
public:
virtual void solve() {std::cout << "A" << std::endl;}
protected:
A(){}
virtual int ReadXML(std::string xml) {return 0;}
friend class SolverFactory;
};
class B : public BaseSolver
{
public:
virtual void solve() {std::cout << "B" << std::endl;}
protected:
B(){}
virtual int ReadXML(std::string xml) {return 0;}
friend class SolverFactory;
};
class SolverFactory
{
public:
static BaseSolver* MakeSolver(std::string xml)
{
BaseSolver* ret = NULL;
if (xml=="A")
{
ret = new A();
}
else if (xml=="B")
{
ret = new B();
}
else
{
return ret;
}
int err = ret->ReadXML(xml);
if (err)
{
delete ret;
ret = NULL;
}
return ret;
}
};
I didn't put any actual XML processing in here because I am lazy, but you could have the factory get the type from the main tag and then pass the rest of the node in. This method ensures great encapsulation, can catch errors in the xml file, and safely separates the behaviors you are trying to get. It also only exposes the dangerous functions (the default constructor and ReadXMLFile) to the SolverFactory, where you (supposedly) know what you are doing.
Edit: in response to the question
The problem you've stated is "I have a B and C of type A, and if is B i want to set "b" settings and if it is C i want to set "c" settings".
Taking advantage of polymorphism, you say "I have a B and C of type A. I tell them to get their settings."
There a couple of ways to do this. If you don't mind mangling your IO with the class, you can simply expose the method:
class BaseSolver
{
public:
virtual void GetSettingsFromCommandLine() = 0;
};
And then create the individual methods for each class.
If you do want to create them separate, then what you want is polymorphism in the io. So expose it that way:
class PolymorphicIO
{
public:
virtual const BaseSolver& get_base_solver() const = 0;
virtual void DoSettingIO() = 0;
};
an example implmentation
class BaseSolverBIO : PolymorphicIO
{
public:
virtual const BaseSolver& get_base_solver() const {return b;}
virtual void DoSettingIO() { char setting = get_char(); b.set_b(setting);}
private:
BaseSolverB b;
};
At first glance this seems like a lot of code (we've doubled the number of classes, and probably need to supply a factory class for both BaseSolver and the IO interface). Why do it?
It is the issue of scaleability/maintainability. Lets say you have figured out a new solver you want to add (D). If you are using dynamic cast, you have to find all the places in your top level and add a new case statement. If there is only 1 place, then this is pretty easy, but if it is 10 places, you could easily forget one and it would be hard to track down. Instead, with this method you have a separate class that has all the specific IO functionality for the solver.
Lets also think of what happens to those dynamic_cast checks as the number of solvers grows. You've been maintaining this software for years now with a large team, and lets say you've come up with solvers up to the letter Z. Each of those if-else statements are hundreds-a tousand of lines long now: if you have an error in O you have to scroll through A-M just to find the bug. Also, the overhead for using the polymorphism is constant, while reflection just grows and grows and grows.
The final benefit for doing it this way is if you have a class BB : public B. You probably have all the old settings from B, and want to keep them, just make it a little bigger. Using this model, you can extend the IO class as well for the io for BB and reuse that code.
One way to achieve this is to add an interface method into the base class:
class BaseSolver{
virtual void SolverMethodToCallFromMain() = 0;
...
};
class SolverA : BaseSolver{
public:
std::string a;
SolverA(TypeA objectA);
virtual void SolverMethodToCallFromMain() {/*SolverA stuff here*/};
};
class SolverB : BaseSolver{
public:
int b;
SolverB(TypeB objectB);
virtual void SolverMethodToCallFromMain() {/*SolverB stuff here*/};
};
And in main:
int main(){
IOService ioService;
BaseSolver* mySolver = ioService.getSolver();
mySolver->SolverMethodToCallFromMain();
}
I am trying to write a message handler whose Base classes are
1-Handler base class
2-Handler Factory that generates proper handler for a proper message type
3-and a base generic class for message
their code is like this:
#include <map>
#include<iostream>
//Base Handler
template<class MSG>
class Handler
{
MSG message;
public:
Handler(MSG message):message(message){
}
virtual void handle() = 0;
MSG getMessage()
{
return message;
}
};
//Base Handler Factory
template<class MSG>
class HandlerFactory {
public:
virtual Handler<MSG> * create(MSG & message) = 0;
};
//Base message
template<class T>
class Message
{
T messageType;
public:
T getMessageType()
{
return messageType;
}
void setMessageType(T messageType_)
{
messageType = messageType_;
}
};
//Then, based on the message type, I write subclass for every base class:
//my custom types
enum MessageType
{
ANNOUNCE,
KEY_SEND,
KEY_REQUEST
};
//my first custom message format
class MyMessage_1 : public Message<MessageType>
{
//...
};
//my first custom handler
class MyMessageHandler_1 : public Handler<MyMessage_1>
{
public:
MyMessageHandler_1(MyMessage_1 &message_): Handler<MyMessage_1>(message_)
{
}
void handle(){}
};
//my custom handler factory
class MyHandlerFactory : public HandlerFactory<Message<MessageType> > {
Handler<Message<MessageType> > *value;
public:
MyHandlerFactory(){};
Handler<Message<MessageType> > * create(Message<MessageType> & message){
switch (message.getMessageType())
{
case ANNOUNCE:
MyMessage_1 t1;
value = new MyMessageHandler_1(t1);//error here
break;
//etc. etc.
default:
value = 0;
break;
};
return value;
};
};
//let's put a main so you can easily compile it
int main()
{
}
the problem is when, in switch-case clause, I try to create an instance of a handler for one of my custom message classes, I get the following error:
templateArgList.cpp: In member function ‘virtual Handler<Message<MessageType> >* MyHandlerFactory::create(Message<MessageType>&)’:
templateArgList.cpp:86:37: error: cannot convert ‘MyMessageHandler_1*’ to ‘Handler<Message<MessageType> >*’ in assignment
I was under the impression that:
Handler<Message<MessageType> > * can be casted as follows:
MyMessageHandler_1-> Handler<MyMessage_1>
^
|
`Message<MessageType>` which finally gives me:
`Handler<Message<MessageType> >` :P
Am I wrong? of course I am, why would I get the above error then :))
I just don't know why and how to fix it.
Therefore I will appreciate if you kindly help me with it.
thanks very much for your kind help
Here is a very simple program that is analogous to what you have done, but without the nested templates so that it's understandable:
#include <vector>
class A {
};
class B : public A {
};
int main() {
std::vector<A>* va;
va = new std::vector<B>;
}
And indeed, g++ gives the error:
error: cannot convert ‘std::vector<B>*’ to ‘std::vector<A>*’ in assignment
This should be clear -- a vector of A's is not the same as a vector of B's, even though B inherits from A. To be able to take advantage of inheritance, you have to have pointers to the objects that are related. For example:
int main() {
std::vector<A*> va(3);
for (int i=0; i<3; ++i) {
va[i] = new B;
}
}
The analogy here is:
std::vector< > ----> Handler< >
A ----> Message<MessageType>
B ----> MyMessage_1
By the way, did you realize that you define a variable named message in both MyMessageHandler_1 and also in Handler<>? This will cause MyMessageHandler_1::message to hide Handler<>::message. I'm not sure if this is what you want.
Also.. you might want to look into the Twisted package for Python, as it might be well suited to the application you're building. (If you don't mind using Python.)
Question: "any suggestion to alter my code?"
Response:
Well, I would try removing the templates and enjoying the power of inheritance. The Handler class can accept a Message object (or reference or pointer), as both of these are base classes. The HandlerFactory's create would also accept a Message object. Then you can proceed with the Message class having an enum MessageType type member variable and using switch inside HandlerFactor to determine the correct Handler-derived class to create.
Or instead of the enum, you could exploit inheritance even further by adding a "NewHandler()" function to Message, which would be pure virtual in Message and would be defined in the derived class. This way, you wouldn't need a switch -- each type of message knows what Handler it needs, and the factor simply calls message->NewHandler().
...It's a bit difficult to determine whether you need to use templates or not because I'm not sure where your project is headed. However, as a rough rule of thumb, it's a good idea to use templates when (a) you want to use equivalent blocks of code for different types and (b) you can't use inheritance to accomplish it. The std::vector<> is a good example -- the behavior of std::vector<int> and std::vector<float> is the same, but int's and float's aren't related by any common base, so rather than rewrite the code for a VectorI and VectorF, the compiler is asked to rewrite the code instead.
So far, it looks like you can exploit inheritance to do what you want. It has the added bonus of making it easier for other people to read your code, as well. :)