如问题所示,
由于我们使用像IsNullOrEmpty或IsNullOrWhiteSpace这样的字符串函数作为函数显示的名称,这些函数执行多个作业,是不是违反了SRP?
相反,它不应该是string.isValid(Enum typeofValidation),而不是使用策略模式来选择正确的策略进行验证。或者在实用程序类或静态类中违反SRP是完全可以的。
答案 0 :(得分:17)
SRP说一个函数或类应该只有一个改变的理由。改变的理由是什么?更改的原因是请求更改的用户。因此,类或函数应该只有一个请求更改的用户。
现在,一个执行某些计算然后进行一些格式化的函数有两个不同的用户可以请求更改。一个会请求更改计算,另一个会请求更改格式。由于这些用户有不同的需求并会提出不同的要求,我们希望他们能够通过不同的功能提供服务。
IsNullOrEmpty(String)不太可能为两个不同的用户提供服务。关心null的用户可能是关心空的用户,因此isNullOrEmpty不违反SRP。
答案 1 :(得分:3)
在面向对象的编程中,单一责任原则规定每个对象应该只有一个责任
您正在描述方法:IsNullOrEmpty或IsNullOrWhiteSpace,它们也是自我描述的,它们不是对象。 string
只有一个责任 - 负责文本字符串!
如果您选择,静态助手可以执行许多任务:单一责任原则的重点是最终使您的代码对于未来的团队和您自己而言更易于维护和可读。正如评论所说,不要过度思考它。你不是在这里设计框架,只是消耗它的一些部分,它将为你清理你的字符串,并验证传入的数据。
答案 2 :(得分: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
视为单一行动可能是非常合理的。
想象一下,为有经验的用户编写一套分步说明,打开文件的“属性”对话框:
现在想象一下,为以前从未使用过鼠标的人写下相同的说明:
当我们编写计算机程序时,我们需要在两个抽象级别上运行。或者,相反,在任何给定时间,我们都在一个抽象层次或另一个抽象层面上运作,以免混淆自己。此外,我们依赖于仍在较低抽象级别运行的库代码。
方法还允许您遵守“不要重复自己”的原则(通常称为“干”)。如果您需要在应用程序的许多部分中序列化和验证对象,则需要使用SerializeAndValidate
方法来减少重复代码。建议您将该方法实现为一种简单的方便方法:
void SerializeAndValidate(SomeClass obj)
{
Serialize(obj);
Validate(obj);
}
这使您可以方便地调用一个方法,同时保留序列化逻辑与验证逻辑的分离,这样可以使程序更易于维护。
答案 3 :(得分:0)
我不认为这不仅仅是一件事。它只是确保您的字符串通过所需的条件。