12

如问题所示,

正如函数名称所示,我们使用 IsNullOrEmpty 或 IsNullOrWhiteSpace 等字符串函数,这些函数不止一项工作,这不是违反SRP吗?

而不是 string.isValid(Enum typeofValidation) 而不是使用策略模式来选择正确的策略来验证。

或者在实用程序类或静态类中违反 SRP 是否完全可以。

4

4 回答 4

17

SRP 说一个函数或类应该只有一个改变的理由。改变的理由是什么?更改的原因是请求更改的用户。因此,一个类或函数应该只有一个请求更改的用户。

现在,一个进行一些计算然后进行一些格式化的函数有两个不同的用户可以请求更改。一个请求更改计算,另一个请求更改格式。由于这些用户有不同的需求,并且会在不同的时间提出他们的请求,我们希望他们有不同的功能。

IsNullOrEmpty(String) is not likely to be serving two different users. The user who cares about null is likely the same user who cares about empty, so isNullOrEmpty does not violate the SRP.

于 2012-03-06T22:00:09.260 回答
3

在面向对象编程中,单一职责原则指出每个对象都应该有单一职责

您正在描述方法:IsNullOrEmpty 或 IsNullOrWhiteSpace,它们的功能也是自我描述的,它们不是对象。string有一个职责——负责文本字符串!

如果您选择,静态助手可以执行许多任务:单一职责原则的全部意义在于最终使您的代码对未来的团队和您自己更具可维护性和可读性。正如评论所说,不要想太多。您不是在这里设计框架,而只是使用其中的某些部分来为您清理字符串并验证传入的数据。

于 2012-03-06T15:58:12.000 回答
2

SRP 适用于类,而不是方法。尽管如此,拥有只做一件事的方法是个好主意。但你不能把它走极端。例如,如果控制台应用程序的 Main 方法只能包含一条语句(并且,如果该语句是方法调用,则该方法也可以只包含一条语句,等等,递归)。

想想 IsNullOrEmpty 的实现:

static bool IsNullOrEmpty(string s)
{
    return ReferenceEquals(s, null) || Equals(s, string.Empty);
}

所以,是的,它做了两件事,但它们是在一个表达式中完成的。如果您进入表达式级别,任何涉及二进制布尔运算符的布尔表达式都可以说是“做不止一件事”,因为它正在评估多个条件的真实性。

如果方法的名称让您感到困扰,因为它们暗示单个方法的活动过多,请将它们包装在您自己的方法中,并使用暗示评估单个条件的名称。例如:

static bool HasNoVisibleCharacters(string s) { return string.IsNullOrWhitespace(s); }
static bool HasNoCharacters(string s) { return string.IsNullOrEmpty(s); }

回应您的评论:

说我写了像 SerilizeAndValidate(ObjectToSerilizeAndValidate) 这样的函数,显然这个方法/类正在做两件事,序列化和验证,显然是一个违规,类中的一些时间方法会导致维护噩梦,就像上面的序列化和验证示例

是的,你担心这一点是对的,但同样,你不能真正拥有只做一件事的方法。请记住,不同的方法将处理不同的抽象级别。您可能有一个非常高级的方法,它SerializeAndValidate作为一长串操作的一部分进行调用。SerializeAndValidate在该抽象级别上,将其视为单个操作可能是非常合理的。

想象一下,为有经验的用户编写一组分步说明来打开文件的“属性”对话框:

  • 右键单击文件
  • 选择“属性”

现在想象为以前从未使用过鼠标的人编写相同的指令:

  • 将鼠标指针放在文件的图标上
  • 按下并释放鼠标右键
  • 出现一个菜单。将鼠标指针放在“属性”一词上
  • 按下并释放鼠标左键

当我们编写计算机程序时,我们需要在两个抽象层次上进行操作。或者,更确切地说,在任何给定时间,我们都在一个抽象级别或另一个抽象级别上操作,以免混淆自己。此外,我们仍然依赖于在较低抽象级别上运行的库代码。

方法还允许您遵守“不要重复自己”的原则(通常称为“DRY”)。如果您需要在应用程序的许多部分中同时序列化和验证对象,您需要一种SerializeAndValidate方法来减少重复代码。建议您将该方法实现为一种简单的便捷方法:

void SerializeAndValidate(SomeClass obj)
{
    Serialize(obj);
    Validate(obj);
}

这使您可以方便地调用一种方法,同时保持序列化逻辑与验证逻辑的分离,这将使程序更易于维护。

于 2012-03-06T16:07:05.303 回答
0

我不认为这会做不止一件事。它只是确保您的字符串通过所需的条件。

于 2012-03-06T15:47:47.187 回答