是否存在用于在子类的数据上实施规则的设计模式
Does a design pattern exist for enforcing rules on the data of a subclass?
假设一个类表示一个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语言中的所有层次结构都将此作为一个通用规则:子类可以做其父类所做的所有事情,并且可以添加其他方法和属性
如果你有特殊的需求,最好是写一份文档,并清楚地说明。
相关文章:
- 防止主数据类型C++的隐式转换
- 用于访问容器<T>数据成员的正确 API
- 嵌套在类中时无法设置成员数据
- 使用流处理接收到的数据
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何用unique_ptr实施零规则
- 如何强制实施有关指针数据成员的常量正确性
- 强制实施调用函数应向被调用函数返回的值添加常量的规则
- 将临时值存储为某种数据类型时,算术运算的标准规则是什么
- 如何使用CRTP实施来修复强大的封装规则
- 如何根据一组规则/条件检查一组数据以进行分类
- 关于实施其中之一的CPP,这三个规则究竟是什么?
- Boost.Spirit(X3,Boost 1.64):如何正确实施此递归规则
- 非静态数据成员和一个定义规则
- 对"non-type"模板参数强制实施规则
- 从不规则文本文件中读取数据到c++中的类
- 什么名称查找规则适用于静态 const 数据成员定义中的名称
- 实施"window"系统和"no deletion of self"规则
- 是否存在用于在子类的数据上实施规则的设计模式