mercredi 26 août 2020

Prototype Design Pattern Questions And Code Review - C++

I have just started reading the GO4 book to learn the OOD concepts. In order to practice the Prototype pattern, I implemented a small example (the idea for colored shapes was taken from "refactoring.guru"). Following is my code with some questions beneath.

Prototype definition:

enum class Shape
{
    Circle,
    Rectangle,
};

class ColoredShapePrototype
{
protected:
    std::string color_;
public:
    ColoredShapePrototype() {}
    ColoredShapePrototype(std::string color) : color_(color) {}
    virtual ~ColoredShapePrototype() {}
    virtual ColoredShapePrototype* Clone() const = 0;
    virtual void ShapeDetails() { std::cout << "Color: " << color_ << "\n"; } 
    virtual void UpdateColor(int color) { color_ = color; }
};

class ColoredCirclePrototype : public ColoredShapePrototype
{
private:
    int radius_;
public:
    ColoredCirclePrototype(std::string color, int raduis) : ColoredShapePrototype(color), radius_(raduis) {}
    ColoredShapePrototype* Clone() const override { return new ColoredCirclePrototype(*this); }
    void ShapeDetails() { ColoredShapePrototype::ShapeDetails(); std::cout << "Radius: " << radius_ << "\n"; }
};

class ColoredRectanglePrototype : public ColoredShapePrototype
{
private:
    int height_;
    int width_;
public:
    ColoredRectanglePrototype(std::string color, int height, int width) : ColoredShapePrototype(color), height_(height), width_(width) {}
    ColoredShapePrototype* Clone() const override { return new ColoredRectanglePrototype(*this); }
    void ShapeDetails() { ColoredShapePrototype::ShapeDetails(); std::cout << "Height: " << height_ << "\nWidth:" << width_ << "\n"; }
};

class ShapesPrototypeFactory
{
private:
    std::unordered_map<Shape, ColoredShapePrototype*> prototypes_;
public:
    ShapesPrototypeFactory() {
        prototypes_[Shape::Circle] = new ColoredCirclePrototype("White", 5);
        prototypes_[Shape::Rectangle] = new ColoredRectanglePrototype("White", 2, 3);
    }
    ~ShapesPrototypeFactory() {
        delete prototypes_[Shape::Circle];
        delete prototypes_[Shape::Rectangle];
    }
    ColoredShapePrototype* CreatePrototype(Shape shape) { return prototypes_[shape]->Clone(); }
};

Usage in main:

ShapesPrototypeFactory prototype_factory;
ColoredShapePrototype* circ = prototype_factory.CreatePrototype(Shape::Circle);
circ->ShapeDetails();
ColoredShapePrototype* rect = prototype_factory.CreatePrototype(Shape::Rectangle);
rect->ShapeDetails();
delete circ;
delete rect;

Questions:

  1. Interfaces in general - pure virtual functions and other variables are declared, and derived classes should implement those. Suppose I want to add a specific capability (with unique data member and member function) to the derived - Does it contradict the interface idea? (Because, if I have a pointer from base to derived, this pointer will not recognize the specific method...). If it is OK, Is there a way to execute a derived function through the interface(who doesnt have this function..)?

  2. while debugging and watching circ variable, I can see the variable in the memory window, and I see "white" color, but I cant find the radius there. Is there a way i can see specific data member address in the memory? (I have tried circ->radius_ etc. none was working..)

  3. I have seen that most implementations are using "unique_ptr". I know its basic usage, but how critical it is? and why not use it all the times rather than a regular pointer actually? and where are the places I should use it in the prototype pattern?

  4. Implementing Copy Constructor in case of non-stack variables (shallow/deep copying) for the clone operation - Is a CCtor in the base class is sufficient or the derived is required as well?

  5. Code review - better syntax/design/ideas/improvements?

Thanks in advance, I will highly appreciate your help!

Aucun commentaire:

Enregistrer un commentaire