假设我有一个类:
class NavigationData
{
float roll;
float pitch;
double latitude;
double longitude;
}
如果我想创建一个方法:
const bool validate() const;
基本上验证4个字段是否包含有效值。
validate()应该是NavigationData类的一部分,还是应该创建一个类似于NavigationDataValidator的东西,它包含一个validate(const NavigationData&)方法。
我只是举一个简单的例子,显然我的真正的课程比这复杂得多。我正在寻找好的OO原则。
换句话说:给定一个方法,我们如何知道它是否属于该类,或者应该属于一个单独的类?
答案 0 :(得分:21)
通常,一个类自己有责任确保它保持逻辑上一致且有效的内部状态。例如,Person
可能有一个构造函数,如果没有这些数据,Person
上的操作毫无意义,则需要使用名字和姓氏。
然而,“逻辑一致且有效”与“在域中有意义”不同,所以有时候外部类的责任是确保遵守域规则。例如,PersonValidator
可能要求Person
拥有位于美国的电话号码。但是Person
不一定需要了解PhoneNumber
是否在美国。
一个好的经验法则是,除了已经属于该类的数据之外,如果需要该类外部的州或域规则,您还需要考虑进行外部验证。如果类的实例的状态可能来自多个源(例如,数据库,Web表单,文件等),您可能还希望将验证集中在外部类中。
答案 1 :(得分:7)
正确的答案是:取决于。
放置这种对象逻辑的自然之处在于对象本身。有时虽然验证规则可能依赖于规则引擎或某种更大的“框架”来验证内容。您不希望在对象内部进行验证的另一种情况是验证属于另一层,层或应用程序(例如视图层)。
答案 2 :(得分:3)
你的类应该以这样的方式设计并提供这样的方法,使validate()始终为真:
此类validate()方法称为类不变量,是Design by Contract的重要组成部分。
答案 3 :(得分:1)
我想说这取决于。如果类的数据可以单独验证,我会将该方法放在类中,但如果验证需要上下文,那么我将基于某个接口创建验证器类。
答案 4 :(得分:1)
...取决于
有时验证不是类本身的一部分,但是业务逻辑,并将其添加到类中会阻止重用,因此,验证类的使用是好的。否则,该类应该能够验证自己。
答案 5 :(得分:1)
我想说只要有效值不依赖于其他类使用NavigationData就可以验证它自己。
基本上,只要纬度和音高必须始终在+/- 90度之间,并且经度和滚动总是在+/- 180度之间,请将验证器保留在班级中。
(顺便说一句,标题怎么样?)
答案 6 :(得分:1)
这取决于具体情况。有时,您的对象在内部绝对有效,但在上下文中,其值是不可接受的。
如果你有简单的数据传输对象,那么它可能不应该验证自己。
如果您有一类Domain Model,那么它应该进行一些验证。
P.S。只是我的个人偏好:当方法返回布尔值时,isValid()而不是validate()。
答案 7 :(得分:0)
正如已经说过的,这取决于。
但在你的情况下,我会寻求一个不同的解决方案,为地理坐标创建新的不可变类
class GeoCoordinates
{
double Latitude;
double Longitude;
}
让本课程验证纬度和经度是否在有效限制范围内。例如,您可能还需要其他地方。
class Airport
{
GeoCoordinates Location;
...
}