你会如何改进这个简单的类以更松散地耦合?

时间:2008-12-08 03:38:03

标签: oop coupling

如下所示,在构造函数中我实例化了一个验证对象,因此我可以用set方法验证用户的电子邮件。这种架构是最佳实践还是有缺陷的?我可以避免让我的User类直接依赖于我的Validation类吗?

Class User {
  Private Email

//constructor
User() {
  Validation = new Validation
}

SetEmail(NewValue) {
  if (Validation.isEmail(NewValue)) {
    Email = NewValue
  }
}

还有一个相关的问题:当set方法收到无效值时,正确的响应是什么?我看到2个选项

  1. 不设置值并返回false
  2. 仍然设置值,但为对象设置错误属性。 (如果设置了User.Error,我知道出了问题)
  3. 我怀疑#1是最佳实践,因为您可以确保任何对象属性的值始终有效。正确的吗?

2 个答案:

答案 0 :(得分:10)

到目前为止,这些建议似乎都有点过分,特别是对于所有IOC和AOP的东西。

  1. User类需要一个电子邮件地址,因此请创建一个EmailAddress类,让User类通过属性和/或其构造函数接受一个。该验证可以像输入EmailAddress引用是否为空一样简单。

  2. EmailAddress类可以是一个简单但通常可重用的实现(考虑基于RFC文档)。它应该是不可变的,并且应该在无效输入上从其构造函数中抛出异常。

  3. 理想情况下,EmailAddress类应该由EmailUserId类(基于RFC?)和InternetDomain类(基于RFC?)组成,因为电子邮件地址是复合数据结构。同样,这些类中的每一个都应该管理不可变实例,并且应该在构造时抛出一个带有无效输入的异常。

  4. “验证”对我来说不是“事物”,而是一种通用的“行动”。因此,它有助于成为一种方法而不是一种类。在这种情况下,我倾向于在每个类中实现验证,作为从构造函数调用的私有静态方法(valid(input)),使用Java或C#等语言。通常,以问题(isValid(input))的形式公开该功能变得很有用。

    编辑:

      

    您是否建议我需要验证的每种不同数据类型都应该拥有自己的类?

    这是解决问题的一种可靠方式,通常称为价值类型(感谢提醒,弗兰克)。结果将是一些(十二个)明确定义的,可重复使用的类,如EmailAddressPhoneNumberPersonName等。所提出的替代方案可能会导致“上帝” “具有不可重复使用,不易测试且难以维护的功能组合”。

    还有其他方法可以对解决方案进行分区,但我的建议确实具有成熟,易于理解和与大量可靠设计原则相一致的优势。我肯定会在尝试发明你自己之前尝试尝试。

答案 1 :(得分:1)

我会:

  1. 通过依赖注入打破与具体Validation对象的耦合:定义一个抽象(纯虚拟)验证类,从中派生一个具体的验证类,并传入(“注入”)对抽象的引用User类的构造函数中的验证类。

    有关如何以及为何在C ++中执行此操作的优秀讨论,请参阅 The C ++ Report 中关于此主题的Robert Martin 1996 article

  2. 不是返回false或静默设置某个属性,而是引发异常。这就是他们的目的。