views:

157

answers:

4

Hello Everyone, here is my problem and I'm considering to use factory method in C++, what are your opinions ?

There are a Base Class and a lot of Subclasses.

I need to transfer objects on network via TCP.

I will create objects in first side, and using this object I will create a byte array TCP message, and send it to other side.

On the other side I will decompose TCP message, I will create object and I will add this object to a polymorphic queue.

A: 

"Parametrized factory method" is a very powerful way of deserializing: get your object and let it do the deserializing based on its data.

stefaanv
Can you be a little more descriptive about "Parametrized factory method"?
metdos
It may be a bit pedant, but it's the name used in the GoF Design Patterns book. It is also known as "Factory" or "Factory Method" although these are more general: "Factory Method" is used for any class that can't be constructed directly (private constructor). With "Parametrized factory method" you pass a parameter to specify what subclass you want.
stefaanv
Just a correction: according to the GoF Design Patterns book. "Factory Method" is mainly used to have an application derived from an abstract application, create an object by using a derived "CreateObject" method. In fact, this isn't used a lot and as such "Factory Method" is now more used to mean "Parametrized factory method" as used in the examples of http://en.wikipedia.org/wiki/Factory_method_pattern (eventhough the UML still shows the original meaning)
stefaanv
A: 

If I understand correctly, your current implementation is error prone, there are many loose ends like processor architecture on both sides, therefore, IMHO, CORBA suits better for your case. Or at least you may use some notation to transfer data. After the transfer, I can suggest Prototype and Visitor patterns to create and initialize your objects. Hope it helps.

baris_a
While I am not much of a fan of "roll-your-own" solutions, I disagree about your assessment that "CORBA suits better for your case". What do you know of the actual situation to decide that processor architecture may be a problem? or that the size of the project allows for the CORBA not-quite-lightweight approach?
p.marino
@p.marino then you should elaborate your question. These are the comments of my answer. Moreover, you are not focusing on Prototype and Visitor pattern approach.
baris_a
I am not the original poster, maybe you are confusing me with metdos?
p.marino
@p.marino then it may be better not to sound like one
baris_a
I still think that CORBA (as its own history has proved, after all) is far from being "lightweight", "easy to develop and deploy" and "the solution to all architectural problems". I understand its role especially when dealing with languages that cannot support reflection (like C++) but you come across like someone who is itching to use CORBA anytime you see an opportunity. Now that you know I am not the original poster why don't you ask him/her nicely what the actual requirements are? Maybe he is dealing with embedded systems, would you suggest CORBA for that too?
p.marino
@p.marino This is pointless.
baris_a
A: 

Depending on your exact requirements I would suggest using the Object-Request-Broker pattern, which can be found in the Pattern Oriented Software Architecture books.

Gabriel Ščerbák
+1  A: 

Short answer: Yes.

Long Answer: The factory method pattern is what you want.

Your network messages need to include the type and size of the object to deserialize in the message header and then on the recipient side your factory method can consume and deserialize the rest of the message body to construct the objects.

A good strategy to make this simple is to have all your classes store the data that they will be serialising and sending over the wire in a private struct. Other non-serialized class data would be outside this struct. That way you can just dump the whole struct on the network with minimal work. Obviously you may have to take into account byte order considerations if you're going cross platform (ie, big to little or little to big endian).

Something like this (I'm sure this is far from perfect as I'm just writing it off the top of my head):

enum VehicleType  
{
  VehicleType_Car,
  VehicleType_Bike
};

class Vehicle 
{
   virtual size_t GetDataSize() = 0;
   virtual void* GetData() = 0;
};

class Bike : Vehicle
{
private:
    VehicleType _type;
    size_t _dataSize;
    struct BikeData
    {
       char[100] name;
       // etc 
    } _data;
public:
    Bike(void* data)
      : Bike(static_cast<BikeData*>(data)->name) 
    {
    }

    Bike(char[]& name) 
      : _type(VehicleType_Bike), _dataSize(sizeof(BikeData))
    {
       memset(&_data.name, 0, 99);
       strncpy(&_data.name, name, 99);
    }

    virtual size_t GetDataSize() { return _dataSize; }
    virtual void* GetData() { return &_data; }
};

class Car : Vehicle
{
    // etc
};


void SendVehicle(int socket, const Vehicle& vehicle)
{
    write(socket, vehicle.GetData(), vehicle.GetDataSize());  
}

Vehicle* ReceiveVehicle(int socket)
{
    VehicleType type;
    size_t dataSize;

    read(socket, &type, sizeof(VehicleType));
    read(socket, &dataSize, sizeof(size_t));

    BYTE* data = new BYTE[dataSize];
    read(socket, &data, dataSize);

    Vehicle v* = CreateVehicle(type, dataSize, data);
    delete[] data;

    return v;
}

// The factory method.
Vehicle* CreateVehicle(VehicleType type, size_t dataSize, void* data)
{
    switch(type)
    {
        case VehicleType_Car: return new Car(data);
        case VehicleType_Bike: return new Bike(data);
    }

    return 0;
}

You could even avoid some memory fragmentation by using the buffer you read off the socket as the Bike's _data structure.

As always, reading up on the pattern you're using is a good idea. Here is the Wikipedia article on the Factory Method Pattern.

You should also look into the Boost Serialization library. It it will help you serialize data across systems with different endianness and word sizes. The method I have detailed above is very simple and doesn't deal with stuff like that.

orj
How this line "Bike(static_cast<BikeData*>(data)->name)"works?Is static cast capable of turning char pointer to struct pointer? Can we sure BikeData points out firstly "name" variable and then other variables in struct?
metdos
static_cast<T*>(void* x) will cast a x that is a void* to T*. Static cast is like the old C style "(T*) x" casts. The code above is a bit unsafe. Ideally you should have the constructor be private and the Bike class be a friend of a class that is the factory. That way only the factory can call the private Bike(void* data) constructor. Alternatively you could change the constructor to be Bike(BikeData* data), ensuring that the conversion from void* is done outside of the Bike constructor.
orj