你会为一个只执行很小一部分功能的类命名,例如,采用定期付款配置文件并将其标记为“失败”。
命名是否正确RecurringPaymentProfileMarkAsFailedService
?我知道这只是一个名字,但我想遵守标准/约定。这是“服务”类应该做的,还是不同的设计模式?我正在尝试遵循 SRP 原则,因此,如果我是正确的,那么最终会有很多小班,每个班专门从事一项任务。我想定义一个正确的命名标准。
你会为一个只执行很小一部分功能的类命名,例如,采用定期付款配置文件并将其标记为“失败”。
命名是否正确RecurringPaymentProfileMarkAsFailedService
?我知道这只是一个名字,但我想遵守标准/约定。这是“服务”类应该做的,还是不同的设计模式?我正在尝试遵循 SRP 原则,因此,如果我是正确的,那么最终会有很多小班,每个班专门从事一项任务。我想定义一个正确的命名标准。
好吧,就其价值而言,从您的描述中听起来您正在使用命令设计模式。
通常当我发现类名太长时,我会使用包或路径层次结构。在这种情况下,它可能类似于:
包:commands.recurringPaymentProfile
类:MarkAsFailed
所以:我使用“命令”而不是“服务”,然后将适用于 recurringPaymentProfile 的那些分组到一个包中。
我相信我理解 SRP 的“精神”,但我个人认为它过分地得出结论,因此您必须为可能应该只是 RecurringPaymentProfileService 上的一个方法 (MarkAsFailed) 创建一个单独的类(假设您描述了这个逻辑作为“功能的一小部分”)。
我认为,当你最终为这样长而笨拙的名字而苦苦挣扎时,这通常表明你在代码结构方面的竞争原则之间没有完全达成正确的平衡。
我的指导原则是,服务应尝试遵守 SRP,因为它与处理(返回/作用于)特定业务实体或流程(例如 PaymentProfiles)尽可能完全相关。但我的倾向是,在尝试将服务的内部拆分到第 n 级时,您可能最终会违反一大堆其他原则。
虽然我从未见过它严格记录在案,但我通常使用“服务”一词来表示处理某些相关最终用户功能子集的类。
例如,假设我有一个银行账户系统,我可能有以下服务:
public class AccountService
{
public boolean transfer(Account src, Account dest, double amt) // ....
public Account create(User user, double initAmt) // ...
public void close(Account account) // ...
}
所以用户可以做的“高级”功能都封装在我的Services中。服务将访问数据库,实例化任何助手,进行计算等它需要的。但就像我说的,这正是我在这个行业中观察到的。
至于 SRP:SRP 并不意味着您需要为每个要执行的功能使用一个全新的类。您不需要一个类将配置文件标记为失败,另一个将其标记为成功,另一个更改配置文件的名称和...
SRP 意味着每个类处理“一件事”,但“一件事”可以是一组密切相关的功能。另一个需要考虑的重要 OO 设计原则是封装。也就是说,一个类应该尽量减少它暴露给客户的东西——只暴露其他人需要的东西。如果您有大量的小类来管理 PaymentProfile 的内部状态,那么您将暴露 PaymentProfile 的所有细节。我给你举个小例子:
假设您的 PaymentProfile 对象有一个布尔值 isSuccess。然后你的类 RecurringPaymentProfileMarkAsFailedService 做这样的事情:
public class RecurringPaymentProfileMarkAsFailedService {
public void mark(PaymentProfile profile)
{
profile.setSuccess(false);
}
}
酷 - 一切都很好。现在我们收到一个功能请求,不仅 PaymentProfile 可以具有“成功”和“失败”状态,而且现在我们需要支持“内部错误”,这意味着某些内部系统在更新期间崩溃了。我们不能再使用布尔值,因此我们将布尔值 isSuccess 更改为可以是以下之一的枚举:SUCCESS、FAILURE、ERROR。现在我们必须重构我们的 MarkAsFailedService。
这是一个微不足道的重构 b/c 它只是一个类,但对于复杂的类树,这些重构可以在整个系统中回显。这表明我透露了太多关于我的 PaymentProfile 的实现细节。一个类应该被封装,因此对其实现的更改对其客户端几乎没有影响。