I have a simple program which draws geometrical figures based on mouse data provided by user. I've got one class which handles the mouse tracking (it gets the List with mouse movement history) and one abstract class called Shape. From this class I derieve some extra Shapes, like Circle, Rectangle, etc. - and every one of them overrides the abstract Draw() function.
It all works nicely, but the problem comes when I want the user to be able to switch desired Shape manually. I get the mouse data and i know what shape should I draw. The problem is how to make the code to "know" which object should it create and pass appropiate parameters to the constructor. It is also impossible at this point to add new Shape derivatives, which is obiously wrong.
I obiously don't want to come out with code like:
List<Shape> Shapes = new List<Shape>();
// somwhere later
if(CurrentShape == "polyline"){
Shapes.Add(new Polyline(Points));
}
else if (CurrentShape == "rectangle"){
Shapes.Add(new Rectangle(BeginPoint, EndPoint));
}
// and so on.
The code above clearly vilates the Open-Closed Principle. The problem is that I don't have any good idea how to get over it. The main problem is that different Shapes have constructors with different parameters, which makes it much more troublesome.
I am pretty sure that this is a common problem, but I don't know how to get past it. Do you have ay idea?
It begs for a factory but not just the factory but factory with injectable workers.
public class Context {
public Point BeginPoint;
public Point EndPoint;
public List Points;
whatever else
}
public class ShapeFactory {
List<FactoryWorker> workers;
public Shape CreateShape( string ShapeName, Context context )
{
foreach ( FactoryWorker worker in workers )
if ( worker.Accepts( ShapeName ) )
return worker.CreateShape( context );
}
public void AddWorker( FactoryWorker worker ) {
workers.Add( worker );
}
}
public abstract class FactortWorker {
public abstract bool Accepts( string ShapeName );
puboic Shape CreateShape( Context context );
}
public class PolyLineFactoryWorker : FactoryWorker {
public override bool Accepts( string ShapeName ) {
return ShapeName == "polyline";
}
public Shape CreateShape( Context context ) { ... }
}
This way the code is open for extensions - new factory workers can be created freely and added to the factory.