Design Problem...Factory or not

R

Rajiv Das

I have run into a design time problem and I look for help.


This is the crux of the design. [Representative]:
class IShape{
public:
virtual void Draw() = 0;
};

class Circle : public IShape{
private:
float _center, _radius;
public:
Circle(float a, float b):_center(a),_radius(b){}
virtual void Draw(){/*Draw it*/}
};

class Square : public IShape{
private:
float _length;
public:
Square(float a):_length(a){}
virtual void Draw(){/*Draw it*/}
};


Constraints:
1. I need to create dynamic collections of different shapes.
2. New shapes made available through plug-ins can be used.
3. New Collections can be defined at run-time.
3. Different shapes can have different constructor parameter lists.


Usage:
typedef std::vector<IShape*> ShapeCollection ;
typedef std::vector<ShapeCollection*> AllShapes;

AllShapes g_MyCollection;

/*based on client layer request create a new collection*/
g_MyCollection.push_back(new ShapeCollection);
g_MyCollection[0]->push_back(new Circle(0.0f, 1.4f));
g_MyCollection[0]->push_back(new Square(5.5f));


My questions are:
1. Should each shape register itself with a factory that supports
variable parameters in the constructor?
[e.g.
http://www.gamedev.net/reference/programming/features/objectfactory/page3.asp]
2. Should all ShapeCollections register themselves in a registry?
[e.g. defineCollection(array of shapes...how do we take care of
parameters??]


Help

Thanks
Rajiv
 
W

werasmus

Hi,

1. I need to create dynamic collections of different shapes.

Some client needs to create dynamic collections of diff shapes... Do
you know values they would use per new shape up front. No. I would
think for that reason a factory may not be your best bet - others may
differ from me, though. A factory would typically be used by a library
(not visible to the client). The client would instantiate an interface
class (not abstract). This interface class would then typically
instantiate the implementation by using an object factory (opaque to
the client). The only thing that the client needs to specify is
typically which concrete factory to instantiate (For example, Win
Factory, Unix Factory etc). Usually the make functions used to create
the factory all have the same constructor parameters. This is not the
case in your scenario.

I think you should use the virtual constructor idiom(also known as
prototyping or cloning). It works as follows:

class IShape
{
public:
virtual void draw() = 0;
virtual IShape* clone() const = 0;
virtual ~IShape(){ ; }
};

class Square : public IShape
{
public:
Square(float a):_length(a){}
virtual void draw(){/*Draw it*/}
virtual void clone() const( return new(*this); }
virtual ~Square(){ ; }

private:
float len_;
};

class AllShapeHolder
{
public:
//...//
void addShape( const IShape& );

private:
typedef std::vector<IShape*> ShapeCollection ;

ShapeCollection shapes_;
}

void AllShapeHolder::addShape( const IShape& newShape )
{
shapes_.push_back( newShape.clone() );
}





2. New shapes made available through plug-ins can be used.
- Virtual constructor...

3. New Collections can be defined at run-time.
- Virtual constructor...

4. Different shapes can have different constructor parameter lists.
- Most certainly Virtual constructor...

I know of one other idiom that you can use - don't know its name
though. I call it the CreationInterface idiom. It is based on the
fact that to create an item, you don't need to be exposed to it's
interface - creation can be delayed:

template <class T>
class CreationIF
{
T* create() const;
};

//Implementation of circle.
void SomeMethod( const CreationIF<ShapeIF>& cIF )
{
someContainer.push_back( cIF.create() );
}

//Implemenation of concrete creator... h file
class CircleCreator : public CreationIF<ShapeIF>
{
public:
CircleCreator( float center, float rad ) : center_( center ), rad_(
rad ){ ; }

//covariant return types? Circle is a ShapeIF
Circle* create() const;

private:
//...
}

//In cpp file...
Circle* CircleCreator::create() const
{
return new Circle( center_, rad_ );
}

There are cases where the above idiom can be essential. Typically,
using the above idiom the client (who knows the creation params but
does not use the rest of the interface) would not need to be exposed to
unnecessary interface).

Regards - hope this helps.

Werner
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top