我有一个方法,它现在需要一个 id。我需要添加一个接受 id 列表的方法。我的选择是让其中一种方法调用另一种方法,如下所示:
void NotifyUsers(List<int> userIds) {//do things}
void NotifyUser(int userId)
{
NotifyUsers(new List<int>{userId})
}
Run Code Online (Sandbox Code Playgroud)
或者我可以将调用更改为NotifyUsers(new List<int>{9999}.
或者我可以使用泛型等。
这里的“最佳实践”是什么?
我知道这有点基于意见的问题,但似乎应该有一个标准,我找不到它。
Eri*_*ert 19
这里的“最佳实践”是什么?
最佳实践是采取整体方法,特别强调调用者的需求。这并不一定意味着为调用者提供最大的灵活性!这意味着了解调用者的用例。
我个人构建此解决方案的方式是:
// Notice: User, not Users. This notifies a single user.
void NotifyUser(int id)
{
// notify the user
}
void NotifyUsers(IEnumerable<int> ids)
{
foreach(var id in ids)
NotifyUser(id);
}
Run Code Online (Sandbox Code Playgroud)
这向调用者强调,如果您想执行一次,请使用NotifyUser,如果您有任何用户序列——不仅仅是一个列表——那么您可以NotifyUsers使用该序列进行调用。
现在我要问的下一个问题是:呼叫者是否想这样做:
NotifyUsers(10, 20, 30);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我会添加第三个函数:
void NotifyUsers(params int[] ids)
{
NotifyUsers((IEnumerable<int>) ids);
}
Run Code Online (Sandbox Code Playgroud)
这种技术对于调用者来说是灵活的,同时确保您的大多数方法都是简单的单行代码。如果 NotifyUser 中有错误,您只想在一个地方修复它。
这种方法的一个缺点是它NotifyUsers()变得合法并且是无操作的。有人可能会不小心调用它并认为它正在做某事。在这种情况下,您可能会强制至少有一个:
void NotifyUsers(int id, params int[] ids)
{
NotifyUser(id);
NotifyUsers((IEnumerable<int>) ids);
}
Run Code Online (Sandbox Code Playgroud)
这说明了一个重要的观点:考虑来电者的需求还涉及对您不认识的人进行心理分析,以弄清楚他们将做错什么,然后在它发生之前加以预防。设计的API,会让人自然而然地只成功是很难!
(另外,请注意这些草图省略了错误处理;您可能想要检查序列和数组是否不为空,等等。)
这里的关键是:从了解调用者的需求开始;设计满足他们需求的 API。然后实施它。也就是说,实施选择应该是什么?
这取决于通知一系列用户的工作方式。我上面勾画的解决方案做了一些假设。他们是:
如果这些假设是错误的呢?考虑一个更新数据库的 API,代价高昂的部分不是更新而是建立与数据库的连接。在这种情况下,您不想写:
void NotifyUser(int id)
{
Connect(); // Expensive
Update(id);
Disconnect();
}
void NotifyUsers(IEnumerable<int> ids)
{
foreach(var id in ids)
NotifyUser(id);
}
Run Code Online (Sandbox Code Playgroud)
因为现在您要为 100 个用户建立 100 个连接。相反,您想翻转脚本:
void NotifyUser(int id)
{
NotifyUsers(Enumerable.Repeat(id, 1));
}
void NotifyUsers(IEnumerable<int> ids)
{
Connect();
foreach(var id in ids)
Update(id);
Disconnect();
}
Run Code Online (Sandbox Code Playgroud)
请注意,在重写实现时,我没有重写 API;请记住,我们已经将 API 设计为对调用者有益,因此如果此 API 满足他们的需求,请不要更改它!方法是抽象的;我们可以更改细节以满足性能要求。(如果我们因为 API 设计问题而无法满足性能目标,那么我们一开始就没有设计出满足调用者需求的 API。)
现在错误处理呢?有很多可能性:
等等。再次非常仔细地考虑调用者的需求。他们期望失败后会发生什么?你知道如何编写逻辑来做调用者期望的事情吗?您能否清楚地记录下来,以便来电者知道是否满足了他们的期望?
如果阵列是代替具体地是可接受的List<>话,可以用该params关键字。例如:
void NotifyUsers(params int[] userIds)
{
//...
}
Run Code Online (Sandbox Code Playgroud)
您可以使用零个或多个参数调用它:
NotifyUsers(123);
NotifyUsers(5, 67, 890);
// etc.
Run Code Online (Sandbox Code Playgroud)