I'm creating a series of objects through a Factory Method pattern. More or less like so:
class CMyFactory
{
public:
virtual CMyObject* MakeObject(ObjectType type);
}
CMyObject* CMyFactory::MakeObject(ObjectType type)
{
CMyObject* newObject = NULL;
switch (type)
{
case type1:
newObject = new CType1Object;
break;
case type2:
newObject = new CType2Object;
break;
// Other cases here
}
return newObject;
}
And now, suppose I want to pass some data to the concrete object created. That data would be different depending on the type of object that I want to create.
Is there a clean way of doing so?
I guess I could pass the data afte开发者_运维百科r creating the object, but that would not fit well with a Factory. The idea of the factory method is to put the logic of object creation in one place only. So if I have to deal with object type-dependant classes later, there's not much difference with creating the object directly of the type I want.
Any ideas on how to solve this? Maybe the Factory Method pattern is not what I need?
One thing you could do is pass it to the constructor, like so:
class CMyFactory
{
public:
virtual CMyObject* MakeObject(ObjectType type, ParamType param);
}
CMyObject* CMyFactory::MakeObject(ObjectType type, ParamType param)
{
CMyObject* newObject = NULL;
switch (type)
{
case type1:
newObject = new CType1Object(param);
break;
case type2:
newObject = new CType2Object(param);
break;
// Other cases here
}
return newObject;
}
You can overload MakeObject according to the parameter type, like this:
class CMyFactory
{
public:
virtual CMyObject* MakeObject(ObjectType type, ParamType param);
virtual CMyObject* MakeObject(ObjectType type, OtherParamType param);
}
CMyObject* CMyFactory::MakeObject(ObjectType type, ParamType param)
{
CMyObject* newObject = NULL;
switch (type)
{
case type1:
newObject = new CType1Object(param);
break;
case type2:
newObject = new CType2Object(param);
break;
// Other cases here
}
return newObject;
}
CMyObject* CMyFactory::MakeObject(ObjectType type, OtherParamType param)
{
CMyObject* newObject = NULL;
switch (type)
{
case type3:
newObject = new CType3Object(param);
break;
case type4:
newObject = new CType4Object(param);
break;
// Other cases here
}
return newObject;
}
Such an approach has the disadvantage that the user of your factory needs to know what kind of parameter it needs to pass for which type of object to be created, but that is probably inevitable with this approach anyway.
I guess I could pass the data after creating the object, but that wouldn't fit well with a Factory. The idea of the factory method is to put the logic of object creation in one place only. So if I have to deal with object type-dependant classes later, there's not much difference with creating the object directly of the type I want.
I agree: you shouldn't need to pass the data to the object after creation. That would amount to a two-step creation which kinda defeats the purpose.
Using a factory method doesn't just hide the way the object is constructed, though: it can also hide the actual type of the object created. A classic example is a WidgetFactory
, which will create all kinds of widgets but will always return a Widget*
allowing your code to take advantage of polymorphism in dealing with the widget created - and allowing the library implementor to change the implementation behind the scenes without breaking any client code
I'm not sure I understand the question correctly. You say you have parameters to pass to the factory method that depend on the type to be created. If you know enough to create the correct set of parameters, (and if ou know what ObjectType to pass), then why have a factory at all, why not just create the objects directly? The idea of a factory is to hide the type, but here you are (implicitly) exposing the type.
Is the data completely different? Or are the objects completely different?
For example, are they all transactions, but one is cash and one is a check and one is a credit card? In which case there would be some commonality in data (amount, date etc) and some that is distinct (card number, for example)?
In this case, you could create a base class (e.g. CTransaction) and have inheritance for CCreditTransaction etc. You could then have your MakeObject take a CTransaction object as well.
If we're talking about CType1Object is a Transaction and CType2Object is an item from an inventory system and CType3Object is some widget then I don't think you'll need to adjust your implementation.
Your factory could be something like MakeTransaction(...) and have a separate factory for MakeWidget(...) and a separate factory for MakeInventoryItem(...) etc
In case of deserializing, this is pretty straightforward: in the serial stream, there is some token (enum type) from which the factory can decide which object to create. Then the serial stream can be passed to the object in a virtual deserialize() function. After all the object knows best what format data in the stream contains for him.
Otherwise, a double dispatch mechanism might be used: you want to create some object, so the data should be compatible. However, double dispatch is not supported in C++, so it is quite a hassle (also with dependecies) to implement.
精彩评论