469,951 Members | 2,492 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,951 developers. It's quick & easy.

Design Problem...Factory or not

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/pro...ory/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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jul 23 '05 #1
1 1453
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jul 23 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Omer van Kloeten | last post: by
reply views Thread by ma740988 | last post: by
5 posts views Thread by ma740988 | last post: by
2 posts views Thread by Mike | last post: by
1 post views Thread by =?Utf-8?B?RXJpYw==?= | last post: by
11 posts views Thread by digz | last post: by
4 posts views Thread by Pallav singh | last post: by
13 posts views Thread by Rafe | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.