As you can see below, in the constructor I'm instantiating a validation object so I can validate a user's email in a set method. Is this architecture best practice or flawed? Can I avoid making my User class directly dependent on my Validation class?
正如您在下面看到的,在构造函数中我实例化了一个验证对象,因此我可以在set方法中验证用户的电子邮件。这种架构是最佳实践还是有缺陷的?我可以避免让我的User类直接依赖于我的Validation类吗?
Class User {
Private Email
//constructor
User() {
Validation = new Validation
}
SetEmail(NewValue) {
if (Validation.isEmail(NewValue)) {
Email = NewValue
}
}
And a related question: When a set method receives an invalid value, what is the proper response? I see 2 options
还有一个相关问题:当set方法收到无效值时,什么是正确的响应?我看到2个选项
- Don't set the value and return false
- Set the value anyway, but set an error property for the object. (so if User.Error is set I know something went wrong)
不要设置值并返回false
无论如何设置值,但为对象设置error属性。 (如果设置了User.Error,我知道出了问题)
I suspect #1 is best practice because you can then assure the value of any object property is always valid. Correct?
我怀疑#1是最佳实践,因为您可以确保任何对象属性的值始终有效。正确?
2 个解决方案
#1
10
The proposals so far all seem to be way overkill, especially with all the IOC and AOP stuff.
到目前为止,这些建议似乎都有点过分,特别是对于所有IOC和AOP的东西。
-
The
User
class needs an email address, so create anEmailAddress
class and have theUser
class accept one via a property and/or its constructor. That validation can be as simple as whether the inputEmailAddress
reference is null or not.User类需要一个电子邮件地址,因此创建一个EmailAddress类并让User类通过属性和/或其构造函数接受一个。该验证可以像输入EmailAddress引用是否为null一样简单。
-
The
EmailAddress
class can be a simple but generally reusable implementation (consider basing it on the RFC document). It should be immutable and should throw an exception from its constructor on invalid input.EmailAddress类可以是一个简单但通常可重用的实现(考虑将其基于RFC文档)。它应该是不可变的,并且应该在无效输入上从其构造函数中抛出异常。
-
Ideally, the
EmailAddress
class should be composed of anEmailUserId
class (based on the RFC?) and aInternetDomain
class (based on the RFC?), since an email address is a composite data structure. Again, each of those classes should manage immutable instances and should throw an exception on construction with invalid input.理想情况下,EmailAddress类应该由EmailUserId类(基于RFC?)和InternetDomain类(基于RFC?)组成,因为电子邮件地址是复合数据结构。同样,这些类中的每一个都应该管理不可变实例,并且应该在构造时使用无效输入抛出异常。
"Validation" strikes me as not a "thing" but rather a generic "action". Therefore, it lends itself to being a method rather than a class. In this case, I tend to implement the validation in each of these classes as a private static method (valid(input)
) that is invoked from the constructor, in languages like Java or C#. Often, it becomes useful to expose that functionality publicly in the form of a question (isValid(input)
).
“验证”让我觉得不是“事物”,而是一种通用的“行动”。因此,它有助于成为一种方法而不是一种类。在这种情况下,我倾向于在每个类中实现验证,作为从构造函数调用的私有静态方法(有效(输入)),使用Java或C#等语言。通常,以问题的形式公开该功能变得有用(isValid(输入))。
EDIT:
Are you suggesting that every distinct data type I need to validate should have it's own class?
您是否建议我需要验证的每种不同数据类型都应该拥有自己的类?
That is one solid way of addressing the issue, commonly known as a Value Type (thanks for the reminder, Frank). The result will be a few (dozen or two) well-defined, reusable classes like perhaps EmailAddress
, PhoneNumber
, PersonName
, etc. The presented alternative is likely to result in a "god class" with a mixture of functionality that is not reusable, not easy to test, and difficult to maintain.
这是解决问题的一种可靠方式,通常称为价值类型(感谢提醒,弗兰克)。结果将是一些(十二个或两个)明确定义的,可重用的类,如EmailAddress,PhoneNumber,PersonName等。所提出的替代方案可能导致具有不可重用的功能混合的“上帝类”,不容易测试,难以维护。
There are other ways to partition the solution, but my suggestion does have the advantage of being mature, well understood, and consistent with a large set of solid design principles. I would certainly recommend trying it before attempting to invent your own.
还有其他方法可以对解决方案进行分区,但我的建议确实具有成熟,易于理解和与大量可靠设计原则相一致的优势。我肯定会在尝试发明你自己之前尝试一下。
#2
1
I would:
-
Break the coupling to the concrete Validation object via dependency injection: define an abstract (pure virtual) Validation class, make a concrete validation class derive from it, and pass in ("inject") a reference to the abstract Validation class in the User class's constructor.
通过依赖注入打破与具体Validation对象的耦合:定义一个抽象(纯虚拟)验证类,从中派生一个具体的验证类,并传入(“注入”)对User类的抽象Validation类的引用构造函数。
For an excellent discussion of how and why to do this in C++, see Robert Martin's 1996 article on the subject from The C++ Report.
有关如何以及为何在C ++中执行此操作的出色讨论,请参阅Robert Martin 1996年关于C ++报告主题的文章。
-
Rather than returning false or silently setting some property, raise an exception. That's what they are there for.
不是返回false或静默设置某个属性,而是引发异常。这就是他们的目的。
#1
10
The proposals so far all seem to be way overkill, especially with all the IOC and AOP stuff.
到目前为止,这些建议似乎都有点过分,特别是对于所有IOC和AOP的东西。
-
The
User
class needs an email address, so create anEmailAddress
class and have theUser
class accept one via a property and/or its constructor. That validation can be as simple as whether the inputEmailAddress
reference is null or not.User类需要一个电子邮件地址,因此创建一个EmailAddress类并让User类通过属性和/或其构造函数接受一个。该验证可以像输入EmailAddress引用是否为null一样简单。
-
The
EmailAddress
class can be a simple but generally reusable implementation (consider basing it on the RFC document). It should be immutable and should throw an exception from its constructor on invalid input.EmailAddress类可以是一个简单但通常可重用的实现(考虑将其基于RFC文档)。它应该是不可变的,并且应该在无效输入上从其构造函数中抛出异常。
-
Ideally, the
EmailAddress
class should be composed of anEmailUserId
class (based on the RFC?) and aInternetDomain
class (based on the RFC?), since an email address is a composite data structure. Again, each of those classes should manage immutable instances and should throw an exception on construction with invalid input.理想情况下,EmailAddress类应该由EmailUserId类(基于RFC?)和InternetDomain类(基于RFC?)组成,因为电子邮件地址是复合数据结构。同样,这些类中的每一个都应该管理不可变实例,并且应该在构造时使用无效输入抛出异常。
"Validation" strikes me as not a "thing" but rather a generic "action". Therefore, it lends itself to being a method rather than a class. In this case, I tend to implement the validation in each of these classes as a private static method (valid(input)
) that is invoked from the constructor, in languages like Java or C#. Often, it becomes useful to expose that functionality publicly in the form of a question (isValid(input)
).
“验证”让我觉得不是“事物”,而是一种通用的“行动”。因此,它有助于成为一种方法而不是一种类。在这种情况下,我倾向于在每个类中实现验证,作为从构造函数调用的私有静态方法(有效(输入)),使用Java或C#等语言。通常,以问题的形式公开该功能变得有用(isValid(输入))。
EDIT:
Are you suggesting that every distinct data type I need to validate should have it's own class?
您是否建议我需要验证的每种不同数据类型都应该拥有自己的类?
That is one solid way of addressing the issue, commonly known as a Value Type (thanks for the reminder, Frank). The result will be a few (dozen or two) well-defined, reusable classes like perhaps EmailAddress
, PhoneNumber
, PersonName
, etc. The presented alternative is likely to result in a "god class" with a mixture of functionality that is not reusable, not easy to test, and difficult to maintain.
这是解决问题的一种可靠方式,通常称为价值类型(感谢提醒,弗兰克)。结果将是一些(十二个或两个)明确定义的,可重用的类,如EmailAddress,PhoneNumber,PersonName等。所提出的替代方案可能导致具有不可重用的功能混合的“上帝类”,不容易测试,难以维护。
There are other ways to partition the solution, but my suggestion does have the advantage of being mature, well understood, and consistent with a large set of solid design principles. I would certainly recommend trying it before attempting to invent your own.
还有其他方法可以对解决方案进行分区,但我的建议确实具有成熟,易于理解和与大量可靠设计原则相一致的优势。我肯定会在尝试发明你自己之前尝试一下。
#2
1
I would:
-
Break the coupling to the concrete Validation object via dependency injection: define an abstract (pure virtual) Validation class, make a concrete validation class derive from it, and pass in ("inject") a reference to the abstract Validation class in the User class's constructor.
通过依赖注入打破与具体Validation对象的耦合:定义一个抽象(纯虚拟)验证类,从中派生一个具体的验证类,并传入(“注入”)对User类的抽象Validation类的引用构造函数。
For an excellent discussion of how and why to do this in C++, see Robert Martin's 1996 article on the subject from The C++ Report.
有关如何以及为何在C ++中执行此操作的出色讨论,请参阅Robert Martin 1996年关于C ++报告主题的文章。
-
Rather than returning false or silently setting some property, raise an exception. That's what they are there for.
不是返回false或静默设置某个属性,而是引发异常。这就是他们的目的。