是否存在用于强制执行子类数据规则的设计模式?

时间:2016-08-17 11:18:49

标签: c++ validation design-patterns

假设一个类代表一个3x3矩阵,并在其构造函数中取9个任意数字,并让该类具有inverse()方法。由于NOT并非所有矩阵都是可逆的,因此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 ++中是否有一种方法可以防止(或者至少清楚地向未来的开发人员发出信号)子类不得引入新的状态或构造函数以避免出现问题(例如切片等)?

3 个答案:

答案 0 :(得分:3)

在这里,您点击了circle/ellipse problem

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

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;
};

答案 1 :(得分:0)

这些约束应该通过接口强制执行,在这种情况下,通过构造函数和任何可能的可用mutator(setter)。这就是你描述的模式。

为了防止未来的开发人员通过继承搞乱您的类的内部,通过声明private来使相关数据成员(即您想要保护的成员)无法访问。

从C ++ 11开始,你也可以声明你的类final,这样任何人都无法继承它。

答案 2 :(得分:0)

在C ++中是否有一种方法可以防止(或者至少清楚地向未来的开发人员发出信号)子类必须不引入新的状态?不幸的是答案是否定的。任何OO语言中的所有层次结构都将其用作通用规则:子类可以完成其父类所做的所有操作,并可以添加其他方法和属性

如果您有特殊要求,您可以做得更好,就是撰写文档并在那里明确说明。