首页 > 解决方案 > 对 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);
        }
    }
}

所以这就是我感兴趣的:

  1. 我是否正确假设在第二个示例中通知类现在可以使用单一责任原则?
  2. show() 方法中发生的所有事情都消失了,但是......它们只是重新定位到控制器中的一个方法,所以这不应该意味着这个控制器方法现在破坏了单一职责吗?如果是这样,如何才能遵守?

标签: oopsolid-principlessingle-responsibility-principle

解决方案


单一责任原则 (SRP) 经常以 Robert C. Martin 的名言形式表述:

一个类应该只有一个改变的理由。

在这种情况下,您的FirstUseNotification课程的目的是向首次使用的用户显示通知。所以这个类需要改变的唯一原因是这个目的是否改变了;这是一个原因,所以 SRP 是满意的。

请注意,此定义适用于类,而不适用于方法。也就是说,将这个方法分成三个方法可能违反了 SRP,因为如果这个类的用户需要调用三个方法而不是一个,那么该用户类有责任检查是否显示通知,并将用户标记为显示,除了用户类自己的责任。FirstUseNotification的职责是“向第一次使用的用户显示通知”,而不是提供允许其他类在不负责时执行此操作的 API。

实际上FirstUserNotification,如果类如何显示通知或访问数据库的详细信息发生更改,则该类可能有其他更改原因。理想情况下,可以通过为通知和数据库类提供稳定的接口来防止这种情况,以便对这些类的更改不需要更改FirstUseNotification显示通知和/或访问数据库的其他类。在实践中,这并不总是 100% 实现的,在这种情况下,FirstUseNotification类可能有一些责任与显示通知或访问数据库的细节有关。但理论上,如果那些其他类处理好自己的职责,那么这个类只有一个改变的理由。


推荐阅读