Best way to implement abstract factory pattern
Consider the following code:
#include <stdio.h>
// =============================
class Shape{
public:
virtual ~Shape(){};
virtual void process() = 0;
};
class Triangle : public Shape{
public:
virtual void process() override {
printf("BBB\n");
}
};
// =============================
/* option 1 */
class TriangleProducer{
public:
Triangle factory(){
return Triangle {};
}
};
/* option 2 */
class PtrShapeProducer{
public:
Shape *factory(){
return new Triangle {};
}
};
/* option 3 */
class PimplShape : public Shape{
Shape *sh;
public:
PimplShape(Shape *sh) : sh(sh){
}
virtual ~PimplShape() override{
delete sh;
}
virtual void process() override {
sh->process();
}
};
class PimplShapeProducer{
public:
PimplShape factory(){
return new Triangle {};
}
};
// =============================
int main(){
TriangleProducer f1;
Triangle tri = f1.factory();
tri.process();
PtrShapeProducer f2;
Shape & sh = *f2.factory();
sh.process();
delete & sh;
PtrShapeProducer f3;
PimplShape psh = f3.factory();
psh.process();
return 0;
}
OPTION 1
That's nice, but it doesn't really provide polymorphism. The return type is known and you must match it. Can be added auto
instead Triangle
, but that doesn't change anything other than making refactoring easier.
OPTION 2
This is how Java and PHP do it. But I realized that "raw" pointers are not desirable in C ++. It can be added std::unique_ptr
, but again it doesn't change anything except for the missing operator delete
.
OPTION 3
This is what someone suggested here a while ago - works well, no "raw" pointers, no deletion. But this is so much code and too complicated - it seems fantastic, but not correct.
OPTION 4 (not implemented here)
Reproduction with const references - however they are constants and do not change the return type of the "factory". I think it looks more like a variation, it is not a real variation.
Any other option I'm missing?
And what's the best option?
source to share
I think the most idiomatic modern C ++ method is the one you mention along the way but ignore. Return a std::unique_ptr<Shape>
.
It's safe, clearly expresses ownership, supports polymorphism, and doesn't need a lot of code.
class ShapeFactory {
public:
std::unique_ptr<Shape> create(){
return std::make_unique<Triangle>();
}
};
But I would not like to argue that this was the "best" method.
Yours PimplShape
in option 3 is actually quite similar to the unique_ptr
equally generic or proven one.
source to share
Your factories run around the property. There is another alternative to this aspect; instead of going around the property, you can make the factory objects of your own:
class Factory {
public:
~Factory() { for(int i=0;i<vec.size();i++) delete vec[i]; }
Shape &build_obj() {
Shape *sh = new Triangle;
vec.push_back(sh);
return *sh;
}
private:
void operator=(const Factory &);
std::vector<Shape*> vec;
};
source to share