首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >原型设计模式C++

原型设计模式C++
EN

Code Review用户
提问于 2020-08-28 15:12:02
回答 1查看 142关注 0票数 1

我刚刚开始阅读GO4的书来学习面向对象的概念。为了实践原型模式,我实现了一个小示例(彩色形状的概念取自"refactoring.guru")。下面是我的代码,下面有一些问题。

原型定义:

代码语言:javascript
复制
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(); }
};

主要用途:

代码语言:javascript
复制
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;

问题:

  1. 接口-纯虚拟函数和其他变量被声明,派生类应该实现这些.假设我想向派生的数据成员和成员函数中添加一个特定的功能(具有唯一的数据成员和成员函数)--它是否与接口思想相矛盾?(因为,如果我有一个从基到派生的指针,这个指针将不会识别特定的方法.)。如果可以的话,有没有办法通过接口执行派生函数(谁没有这个函数..)?
  2. 在调试和查看circ变量时,我可以在内存窗口中看到变量,也可以看到“白色”颜色,但我在那里找不到半径。有没有办法在内存中看到特定的数据成员地址?(我试过中国保监会->radius__等,没有一个起作用。)
  3. 我已经看到大多数实现都使用"unique_ptr“。我知道它的基本用法,但它有多重要?为什么不经常使用它而不是一个普通的指针呢?在原型模式中,我应该在哪里使用它呢?
  4. 在非堆栈变量(浅/深复制)的情况下为克隆操作实现复制构造函数-基类中的CCtor是足够的还是需要派生的?
  5. 代码评审-更好的语法/设计/想法/改进?

提前谢谢,我将非常感谢您的帮助!

EN

回答 1

Code Review用户

发布于 2020-09-02 04:29:16

让我们复习一下你的问题。

  1. 不,这和这个想法并不矛盾。基类应该定义派生类的公共功能,这是某些系统对此类对象进行操作所需要的。但是,该系统的部分代码或代码库的另一部分可能只用于处理某些派生类,在这种情况下,不应该在基类中定义函数和变量。使用您的示例,呈现系统可能需要一个Render()方法和变量来定义形状的视觉特征,这些特征应该是有色形状接口的一部分。另一方面,与有角的形状一起工作的系统不会被期望在圆圈上工作。在这种情况下,您将在该系统中将形状dynamic_cast为派生类型,并调用特定于派生类的方法。
  2. 根据您使用的调试器,您可能使用一个监视窗口来查看circ变量的值。手表窗口将显示circ为一个类型为ColoredShapePrototype*的变量,该变量只有一个颜色变量。例如,在Visual中,通过输入( ColoredCirclePrototype* )circ,“监视”窗口将允许您将变量强制转换为ColoredCirclePrototype*。然后你会看到中国保监会的半径成员。
  3. 智能指针避免了管理动态分配内存的常见问题。unique_ptr通过在作用域末尾释放内存来特别避免泄漏,除非它被移动到另一个unique_ptr。如果克隆()函数返回一个unique_ptr,这意味着原型模式代码的用户不必费心记住释放内存。但是,您强制他使用智能指针的特定实现,在本例中是标准库的unique_ptr。如果此原型模式是库的一部分,并用于具有不同的unique_ptr实现的项目,则管理这种差异可能比返回普通的原始指针更复杂。
  4. 如果派生类的成员需要深度复制,那么该类需要定义一个执行深度复制的复制构造函数。
  5. 我的反馈
  • 我看到的最重要的问题是,其他人可以进一步从派生类派生类,没有什么可以提醒他们克隆方法需要被覆盖。让我们考虑创建继承ColoredSquarePrototype的ColoredRectanglePrototype。如果我们创建一个square对象并尝试克隆它,那么我们将调用ColoredRectanglePrototype::Cl续()来复制一个矩形,而不是一个正方形。这并不容易解决,一个选项是声明您的派生类是最终的,因此它们不能进一步派生。如果您希望允许派生,您可以在以下博客文章中进一步阅读这个问题:https://katyscode.wordpress.com/2013/08/22/c-polymorphic-cloning-and-the-crtp-curiously-recurring-template-pattern/
  • 我看不到在ColoredShapePrototype中提供默认构造函数的好处,它只允许使用带有统一颜色("")的形状。
  • 您应该向构造函数传递一个const字符串&以避免复制。
  • 从形状类的名称中删除"Prototype“将更好地传达这样的信息:这些类代表实际的形状,而不是一些辅助实现。
  • 虚拟空UpdateColor(int颜色)不正确地接受整数参数而不是字符串。这将进行编译,因为整数被转换为用于调用std::string::operator=(const )的字符。
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/248553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档