I have a library for 3D geometry. The library has classes like Point, Vector, Axis, Plane etc. The library has an interface and implementation hierarchy but simply all classes inherits from GeometryObject class.
class Point : public GeometryObject;
class Vector : public GeometryObject;
class Axis : public GeometryObject;
class LinePiece : public GeometryObject;
class Plane : public GeometryObject;
Each class has a numbber of constructors, for example:
Point::Point(){}
Point::Point(std::array<double, 3> theCoords){}
Vector::Vector(std::array<double, 3> theComponents){}
Axis::Axis(const Point& thePoint1, const Point& thePoint2){}
Axis::Axis(const Point& thePassingPoint, const Vector& theDirectionVector){}
Plane::Plane(const Point& thePoint1, const Point& thePoint2, const Point& thePoint3){}
Plane::Plane(const Point& thePassingPoint, const Vector& theNormalVector){}
As seen, the constructors have different signature. Only Point class has a default ctor.
Currently, the library does not have an API. The users of the library must include the header for each geometry object they intent to use. But i want to access the library through a single interface.
#include<cs.hxx>
#include<Point2D.hxx>
#include<Point3D.hxx>
#include<Vector2D.hxx>
#include<Vector3D.hxx>
#include<Axis.hxx>
#include<LinePiece.hxx>
#include<Circle.hxx>
#include<Plane.hxx>
int main()
{
Point3D point1 { Point3D(std::array<double, 3>{ 11., 12., 13. }) };
// Other objects
}
The user code if i have a Creator would be:
#include<Creator.hxx>
int main()
{
Point3D point1 { Creator::createPoint3D(std::array<double, 3>{ 11., 12., 13. }) };
// OR with a builder for example
Builder builder = Builder("Point3D", std::array<double, 3>{ 11., 12., 13. }) // Just an example
GeometryObject point2 { Creator::create(builder) };
// Other objects
}
Hence, i want to create a creator class to act as the API of the library.
Starting from here, i will use static creator functions for simplicity. Depending on the design pattern (abstract factory, or factory method or builder,..), the design will be different.
The creator class would simply be defined:
class Creator {
static GeometryObject create(...);
}
or
class Builder {
Builder(...);
}
class Creator2 {
static GeometryObject create(const Builder&);
}
I left "..." for the parameters as the constructors vary for each object. A direct solution is to create a static member function for each constructor:
class Creator {
static Axis createAxis(const Point& thePoint1, const Point& thePoint2);
static Axis createAxis(const Point& thePassingPoint, const Vector& theDirectionVector);
}
However, the creator class is fully coupled with the library implementation. Any change in the library must be reflected to Creator too. For example, when a new constructor is added to a class in the library, the Creator must be updated. I studied abstract factory, factory method and builder design patterns. As i understand, a creator class must be independent on the definitions of the classes to be created. But i could not manage the varying constructor problem.
Am i right to have a creator design pattern as my API? How can i create the Creator class which is separated (decoupled) from the implementation of the geometry library? Which design pattern should i use?
Note: Only the Point has a default ctor as i mentioned. The other objects dont as physically not possible. For example a Vector cannot have all components zero. I could assign default values. For example, for the Plane, a default value would be the x-y plane of the global coordinate system. But, a Plane object has two members: a Point and a Vector. Hence, when i create the default Plane, i have to create a Point and a Vector. However, the user of the library would not be aware of these Point and Vector objects which is i think not a good design. Another solution is to have deault constructors which create uncomplete objects. But this breakes RAII and is not preferable. Hence, i removed default ctors accept for the Point.