对 OOP 中单一职责的困惑
Confusion about single responsibility in OOP
让我们考虑以下示例:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// check if it was already shown, return if so
// show a notification
// mark it as shown in the db or whatever
}
}
class SomeController
{
function someMethod()
{
firstUseNotification->show(user);
}
}
show() 方法似乎通过做 3 件事打破了单一职责。所以我认为这可以这样重写:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// show a notification
}
function shouldShow(User user)
{
// return true if not yet shown
}
function markAsShown(User user)
{
// flag notification as shown
}
}
class SomeController
{
function someMethod()
{
if (firstUseNotification->shouldShow(user))
{
firstUseNotification->show(user);
firstUseNotification->markAsShown(user);
}
}
}
我感兴趣的是:
- 我假设在第二个示例中,通知 class 现在符合单一责任原则是否正确?
- show() 方法中发生的所有事情都消失了,但是......它们只是重新定位到控制器中的一个方法,所以这不应该意味着这个控制器方法现在打破了单一职责吗?如果是这样,如何才能做到合规?
单一责任原则 (SRP) 通常以 Robert C. Martin 的引述形式表述:
A class should have only one reason to change.
在这种情况下,您 FirstUseNotification
class 的目的是向首次使用的用户显示通知。所以这个 class 需要改变的唯一原因是这个目的改变了;这是一个原因,所以SRP是满意的。
请注意,此定义适用于 class,不适用于方法。也就是说,将此方法拆分为三个方法可能 违反 SRP,因为如果此 class 的用户需要调用三个方法而不是一个,那么该用户 class 有责任检查是否显示通知,并将用户标记为所示, 除了 用户 class 自己的责任。 FirstUseNotification
的责任是 "show a notification to a first-time user",而不是提供一个 API 允许其他 class 在他们没有责任的情况下这样做。
实际上,FirstUserNotification
class 可能有其他更改原因,如果它如何显示通知或访问数据库的详细信息发生更改。理想情况下,可以通过为通知和数据库 classes 提供稳定的接口来避免这种情况,因此对那些 classes 的更改不需要更改 FirstUseNotification
或其他 class显示通知 and/or 的 es 访问数据库。实际上,这并不总是 100% 实现,在这种情况下,FirstUseNotification
class 可能有一些责任与显示通知或访问数据库的细节有关。但理论上,如果其他 class 正确处理了自己的职责,那么这个 class 只有一个改变的理由。
让我们考虑以下示例:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// check if it was already shown, return if so
// show a notification
// mark it as shown in the db or whatever
}
}
class SomeController
{
function someMethod()
{
firstUseNotification->show(user);
}
}
show() 方法似乎通过做 3 件事打破了单一职责。所以我认为这可以这样重写:
class User
{
}
class FirstUseNotification
{
function show(User user)
{
// show a notification
}
function shouldShow(User user)
{
// return true if not yet shown
}
function markAsShown(User user)
{
// flag notification as shown
}
}
class SomeController
{
function someMethod()
{
if (firstUseNotification->shouldShow(user))
{
firstUseNotification->show(user);
firstUseNotification->markAsShown(user);
}
}
}
我感兴趣的是:
- 我假设在第二个示例中,通知 class 现在符合单一责任原则是否正确?
- show() 方法中发生的所有事情都消失了,但是......它们只是重新定位到控制器中的一个方法,所以这不应该意味着这个控制器方法现在打破了单一职责吗?如果是这样,如何才能做到合规?
单一责任原则 (SRP) 通常以 Robert C. Martin 的引述形式表述:
A class should have only one reason to change.
在这种情况下,您 FirstUseNotification
class 的目的是向首次使用的用户显示通知。所以这个 class 需要改变的唯一原因是这个目的改变了;这是一个原因,所以SRP是满意的。
请注意,此定义适用于 class,不适用于方法。也就是说,将此方法拆分为三个方法可能 违反 SRP,因为如果此 class 的用户需要调用三个方法而不是一个,那么该用户 class 有责任检查是否显示通知,并将用户标记为所示, 除了 用户 class 自己的责任。 FirstUseNotification
的责任是 "show a notification to a first-time user",而不是提供一个 API 允许其他 class 在他们没有责任的情况下这样做。
实际上,FirstUserNotification
class 可能有其他更改原因,如果它如何显示通知或访问数据库的详细信息发生更改。理想情况下,可以通过为通知和数据库 classes 提供稳定的接口来避免这种情况,因此对那些 classes 的更改不需要更改 FirstUseNotification
或其他 class显示通知 and/or 的 es 访问数据库。实际上,这并不总是 100% 实现,在这种情况下,FirstUseNotification
class 可能有一些责任与显示通知或访问数据库的细节有关。但理论上,如果其他 class 正确处理了自己的职责,那么这个 class 只有一个改变的理由。