是否存在用于在子类的数据上实施规则的设计模式

Does a design pattern exist for enforcing rules on the data of a subclass?

本文关键字:数据 实施规则 设计模式 子类 存在 用于 是否      更新时间:2023-10-16

假设一个类表示一个3x3矩阵,并在其构造函数中取9个任意数字,并让该类有一个逆()方法。由于并非所有矩阵都是可逆的,因此inverse()方法返回一个可选值(或一个可空指针),调用方必须在运行时检查该值。

然而,某些3x3矩阵总是可逆的,只要矩阵中的值遵循一定的规则,例如3D旋转矩阵。我们可以编写一个子类,它不允许直接构造,但可以使用一些特殊的规则来构造,例如围绕笛卡尔轴的旋转角度。

最终结果是这个层次结构,它应该允许层次结构的客户端在使用子类时具有编译时安全性(例如,客户端可以保证object.rotate(rotationMatrix.inverse())始终工作,假设rotationMatrix的类型是rotationMatrix):

class Matrix {
 public:
  Matrix(double e_0_0, double e_0_1, double e_0_2,
         double e_1_0, double e_1_1, double e_1_2,
         double e_2_0, double e_2_1, double e_2_2) {
      ...
  }
  std::unique_ptr<Matrix3x3> inverse() const {
    if (isInvertible) {
      return std::unique_ptr(new Matrix3x3(...));
    }
    return std::unique_ptr();
  }
}
class RotationMatrix : public Matrix3x3 {
 public:
  static RotationMatrix getRotationAroundX(double angle) {
    return asRotationMatrix(Matrix(1,          0,           0,
                                   0, cos(angle), -sin(angle),
                                   0, sin(angle), cos(angle)));
  }
  RotationMatrix inverse() const {
    return asRotationMatrix(*Matrix::inverse().get()));
  }
 private:
  static const RotationMatrix3D& asRotationMatrix(const Matrix3x3& matrix) {
    return static_cast<const RotationMatrix3D&>(matrix);
  }
}

分解原来的问题:

  • 除了上面描述的模式之外,是否还有其他模式来实现此功能?
  • 如果没有其他模式存在,c++中是否有一种方法可以防止(或至少清楚地向未来的开发人员发出信号)子类绝对不能引入新的状态或构造函数,以避免强制转换问题(例如切片等)?

这里,你遇到了圆/椭圆的问题:

最好区分不同的类并使用组合:

class RotationMatrix {
public:
    static RotationMatrix getRotationAroundX(double angle) {
        return { Matrix(1,          0,           0,
                        0, cos(angle), -sin(angle),
                        0, sin(angle), cos(angle))};
     }
     RotationMatrix inverse() const {
        return {*Matrix::inverse().get()});
     }
     const Matrix3x3& AsMatrix() const { return matrix; }
 private:
     static RotationMatrix(const Matrix3x3& matrix) : matrix(matrix) {}
     Matrix3x3 matrix;
};

这些约束应该通过接口强制执行,在本例中是通过构造函数和任何可能可用的mutator (setter)强制执行。这正是你所描述的模式。

为了防止将来的开发人员通过继承搞乱你的类的内部,通过声明private使相关的数据成员,即那些你想要保护的,不可访问。

从c++ 11开始,你也可以声明你的类final,这样就没有人可以从它继承了

在c++中是否有一种方法可以防止(或者至少清楚地告诉未来的开发人员)子类绝对不能引入新的状态?不幸的是,答案是否定的。任何OO语言中的所有层次结构都将此作为一个通用规则:子类可以做其父类所做的所有事情,并且可以添加其他方法和属性

如果你有特殊的需求,最好是写一份文档,并清楚地说明。