Is factory method appropriate here?
I am generating a sequence of Step
objects that differ by "Type" and data contained within. e.g:
The Step
objects should basically be structs that look like this
{ GRAB, CASCADE_ONE, FACEUP, SOMEOTHERDATA },
{ DROP, DECK, FACEDOWN, MOREDATA, ANDSOMEMORE },
{ MOVE, 34, 89 },
where GRAB
, MOVE
and DROP
indicate StepType
:
typedef enum
{
开发者_StackOverflow社区 GRAB,
DROP,
MOVE
}StepType;
As you can see, depending on StepType
, these structs each have variable numbers of data fields after the StepType
.
I plan to iterate over a sequence of these structs and perform a particular action based on the StepType
field. My first hunch is that these should be objects of classes derived from an abstract Step
class - i.e. I should create a GrabStep
class, a MoveStep
class and a DropStep
class.
Is this a good design and if so should I create them using a factory method? If a factory method is the way to go, then how to initialise the fields within the objects?
You don't need the factory pattern for this. But creating an abstract Step
class is a good start:
class Step
{
private:
// The presence of a pure virtual makes this class abstract.
virtual void DoAction() = 0;
public:
virtual ~Step() {} // Needed if you are going to delete via a Step* pointer
void Action() { DoAction(); } // Template method pattern
};
// All other classes derive publicly from Step, since they all have an "is-a"
// relationship with Step (i.e. a GrabStep "is-a" Step).
class GrabStep : public Step
{
private:
void DoAction() { /* Do whatever a GrabStep does */ };
// Data relevant to GrabStep
};
class MoveStep : public Step
{
private:
void DoAction() { /* Do whatever a MoveStep does */ };
// Data relevant to MoveStep
};
class DropStep : public Step
{
private:
void DoAction() { /* Do whatever a DropStep does */ };
// Data relevant to DropStep
};
Then, you can iterate over these things without having to know their exact types:
// Example:
std::vector<Step*> seq; // or some other container
// Note that we are storing Step* pointers in a container instead of Step
// objects. This is needed for polymorphism to work.
// ...
seq.push_back(new GrabStep);
seq.push_back(new MoveStep);
seq.push_back(new DropStep);
// ...
for(std::vector<Step*>::iterator i = seq.begin(); i != seq.end(); ++i)
{
// Will call the proper version of DoAction() depending on the actual type.
(*i)->Action();
}
// ...
// After we are done, clean up after ourselves. This is needed because
// std::vector does not delete the pointees.
for(std::vector<Step*>::iterator i = seq.begin(); i != seq.end(); ++i)
{
delete (*i); // Safe because Step has a virtual destructor.
}
From the sounds of it all you need is polymorphism of some kind, which you're onto with the abstract base class.
The factory pattern is when the caller don't care about the type of the object they're going to need, only that it conforms to an interface. For instance, a parser of a config file that doesn't care where the config file lives or if it's binary or xml. All the parser wants to do is read elements.
In your case whatever code is choosing which step type to construct by definition cares about which object type they're creating. You can still use the factory pattern to abstract away the construction, but you're going to need one factory function (with the relevent parameters) per step type.
Depending on what methods you use to decide which step type to construct, you may want to abstract them away into a strategy pattern or similar.
If you need run-time polymorphism, then I think it's a good design. Regarding the factory function: if your clients need one, then write one. The factory function simply calls the constructors of the subclasses.
精彩评论