验证方法的参数
我有一个关于当参数包含在对象中时验证方法参数的最佳实践的问题。例如,如果:
public class Student {
public int getStudentId();
public String getStudentName();
public String getStudentSSN();
public double getStudentGpa();
public String getStudentMajor();
// Other student related getters
}
那么,我有一个方法:
public void printStudentReport(Student student);
在这个方法中,我需要执行涉及ID、姓名、GPA、专业的逻辑。所以,这些就是所需要的。所有其他学生获取者都不必填充。可以先验证 Student 对象,然后验证我需要的这四个方法吗?我觉得这有点误导,因为我将此 Student 对象传递给此方法,但并非所有字段都是必需的,因此它实际上是发送到此方法的半填充对象。我觉得很奇怪。
I have a question on the best practice for validating arguments to a method when the arguments are contained within an object. For example, if you have:
public class Student {
public int getStudentId();
public String getStudentName();
public String getStudentSSN();
public double getStudentGpa();
public String getStudentMajor();
// Other student related getters
}
Then, I have a method:
public void printStudentReport(Student student);
In this method, I need to perform logic involving the ID, name, GPA, and major. So, those are the ones required. All the other student getters don't have to be populated. Is it ok to just first validate the Student object and then those four methods I need? I feel like this is a bit misleading because I am passing this Student object to this method, yet not all fields are required, so its really a half-populated object being sent to this method. Just seems strange to me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果某些属性必须始终填充以使 Student 有效,则应考虑使用所需参数定义非默认构造函数,并从类中删除任何默认构造函数(如果需要,请验证getter 中的属性值)。这确保只能创建有效的 Student 对象。
如果其他属性对于学生来说确实是可选的,那么对我来说看起来完全没问题。当然,您需要仔细思考用例并仔细分析领域模型,以便决定哪些参数是必需的,哪些参数是可选的。
If some of the properties must be populated always for a Student to be valid, you should consider defining a nondefault constructor with the required parameters, and removing any default constructors from the class (and if needed, validating the property values within the getters). This ensures that only valid Student objects can be created.
If the other properties are really optional for Students, it looks perfectly OK to me. Of course, you need to think through the use cases and analyze the domain model carefully, in order to decide which parameters are required and which are optional.
想想您正在创建的概念:学生报告。该方法仅使用一组学生数据并不重要,因为这些是您的报告的当前要求。也许他们将来会改变。也许他们不会。但这似乎是正确的设计,因为它更能适应变化。
现在验证更加棘手。该报告是否需要与学生正常验证不同的特殊验证?如果是这种情况,那么请务必在报告中对其进行验证:
但是,如果验证对于一组客户端是常见的(可能对于
printStudentReport
和saveStudentInDatabase
),那么您可以创建一个验证类:您可以为不同类型的学生验证提供不同的类。
但是,如果验证对于整个系统来说是常见的,那么我更愿意将其放在
Student
类本身中,或者在它填充到学生实例中时对其进行验证。Think about the concept you're creating: a student report. It shouldn't matter that the method uses only a set of the student data, because those are the current requirements for your report. Maybe they'll change in the future. Maybe they won't. But it just seems like the right design, because it's more resilient to change.
Now the validation is trickier. Does the report need a special kind of validation, different than the normal validation for students? If that's the case, then by all means, validate it in the report:
But if the validation is common for a set of clients (maybe for
printStudentReport
and forsaveStudentInDatabase
), then you could create a validation class:You'd have different classes for the different types of student validation.
But, if the validation is common for the whole system, than I'd prefer to put it in the
Student
class itself, or validate it as it's populated in a student instance.如果您只需要 Student 的 4 个属性,那么我强烈建议您更改方法以单独获取它们。
这样,您就可以将打印方法与 Student 分离,并享受由此带来的所有好处。
If you only need 4 attributes from Student then I would highly recommend just alteringyour method to take them individually.
That way you decouple your print method from Student, with all the benefits that brings.
一种选择是让 Student 对象在创建时(以及编辑期间)验证其数据,因此当您传递 Student 对象时,您始终可以确保它们是有效的。
但假设在程序的所有区域中,相同的验证约束将应用于 Student 对象,因此可能不是一个选项。
One option is to have the Student object validate it's data apon creation (and during edits), so while you're passing around Student objects you can always be sure they're valid.
But that has the assumtion that in all areas of the program the same validation constraints will apply to the Student object, so may not be an option.
半填充的物体很常见。特别是如果您无法控制填充对象的数据源。我说只验证 printStudentReport() 所需的 Student 字段就可以了。我经常编写类似的报告生成方法,这些方法根据必要的数据进行验证,但会提供对象的任何额外数据(如果存在)。
Half-populated objects are quite common. Especially if you don't have control of the data source populating your objects. I say it would be just fine to only validate the Student fields that are required for printStudentReport(). I often write similar report-generating methods that validate based on the data that is necessary but will provide any extra data from the object if it is present.
您还可以尝试接口方法,而不是传递学生对象,而是传递接口。这意味着您可以拥有仅实现对象的该部分的学生对象。
该接口可以包含一个验证方法
You could also try the interface approach, instead of passing a student object, you pass an interface. This means you can have student objects that only implement that part of the object.
the interface could then contain a method for validation
我想到的一个问题是,该逻辑到底是报告逻辑还是学生逻辑。在报告中,您可以编码:
或者只是
我的看法是,有些东西可能属于学生。
因此,我们得到的情况是,我们无法计算事物,因为 X、Y 或 Z 中的某些未正确初始化。因此调用 getThing() 可能会抛出异常,但这感觉很奇怪。为什么一个对象应该提供一些 getThing() 功能但后来却无法做到这一点?
在我看来,您的 Student 类需要重构。学生可以执行一组核心功能,并且它们足以生成某些报告。因此,您可以使用 IRegistered 接口和更丰富的 IActiveStudent 接口。您的报告类需要 IRegistered,其他类需要 IActiveStudent。
各种学生对象在其生命周期中都会改变其能力,就像毛毛虫变成飞蛾一样。您在毛毛虫上没有 Fly() 方法,因此您不需要在所有鳞翅目类上使用 canYouFlyYet() 方法。
One question that occurs to me is whether the logic really is Report logic or Student logic. In report you could code:
or just
My take is that probably some stuff belongs in student.
So then we get the case, that we can't compute thing because some of X, Y or Z are not correctly initialised. So calling getThing() might throw an exception, but that feels weird. Why should an object offer some getThing() capability but then not be able to do it?
It seems to me that your Student class is in need of refactoring. There's a core set of capabilities that Students can do and they're sufficient to allow certain reports to be produced. Hence you've got say IRegistered interface and a richer IActiveStudent interface. Your report class needs an IRegistered and other classes need IActiveStudent.
Various Student objects change their capabilities in their lifetime, rather like a Caterpiller turns into a Moth. You don't have a fly() method on a caterpiller, and hence you don't need a canYouFlyYet() method on all your lepidoptra classes.