了解使用单一责任原则的实际好处

Joh*_*n H 15 c# single-responsibility-principle solid-principles

我正在努力了解SRP,但是,虽然我理解了如何应用它的原因,但我并没有真正看到这样做的好处.考虑这个例子,取自Robert Martin的SRP PDF:

interface IModem
{
    void Dial(string number);
    void Hangup();
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

他建议将其分为两个界面:

interface IModemConnection
{
    void Dial(string number);
    void Hangup();
}

interface IModemDataExchange
{
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

我也一直在阅读这篇文章,它更进了一步:

interface IModemConnection : IDisposable
{
    IModemDataExchange Dial(string number);
}

interface IModemDataExchange
{
    void Send(char c);
    char Recv();
}
Run Code Online (Sandbox Code Playgroud)

在这一点上,我理解functional(Send / Recv)和non-functional(Dial / Hangup)方面的含义,但我没有看到在这个例子中分离它们的好处.考虑到这个基本实现:

class ConcreteModem : IModemConnection
{
    public IModemDataExchange Dial(string number)
    {
        if (connection is successful)
        {
            return new ConcreteModemDataExchange();
        }

        return null;
    }

    public void Dispose()
    {
        // 
    }

    public bool IsConnected { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

在这一点上,让我再次引用罗伯特马丁,即使他正在谈论与PDF不同的例子:

其次,如果对GraphicalApplication的更改导致Rectangle由于某种原因而发生更改,则该更改可能会强制我们重建,重新测试和重新部署ComputationalGeometryApplication.如果我们忘记这样做,该应用程序可能会以不可预测的方式破坏.

这是我不明白的.如果我必须创建第二个实现IModemDataExchange,并且我想要使用它,我仍然需要更改Dial方法,这意味着该类也需要重新编译:

public IModemDataExchange Dial(string number)
{
    if (some condition is met)
    {
        return new ConcreteModemDataExchange();
    }
    else if (another condition is met)
    {
        return new AnotherConcreteModemDataExchange();
    }

    return null;
}
Run Code Online (Sandbox Code Playgroud)

我无法看到这样做是为了减少改变对班级的影响.它仍然需要重新编译,那么有什么好处呢?你从这样做中获得了什么,这对于生产高质量的代码非常重要?

Pat*_*irk 10

对我来说,上面的调制解调器示例总是看起来像接口隔离原则而不是SRP的情况,但除此之外.

在你关于这个问题的部分中Rectangle,我认为你只是误解了它.Martin使用Rectangle作为共享库的示例.如果GraphicalApplication需要一个新方法或更改Rectangle类中的语义,那么这会影响ComputationalGeometryApplication因为它们都"链接"到Rectangle库.他说它违反了SRP,因为它负责定义渲染边界和代数概念.想象一下,如果GraphicalApplication从DirectX更改为OpenGL,其中y坐标被反转.您可能希望更改一些内容Rectangle以促进此操作,但您可能会导致更改ComputationalGeometryApplication.

在我的工作中,我尝试遵循SOLID原则和TDD,并且我发现SRP使得为类编写测试变得简单并且还使课程集中.遵循SRP的类通常非常小,这降低了代码和依赖性的复杂性.在删除课程时,我会尝试确保课程要么"做一件事",要么"协调两件(或更多件事)".这使他们保持专注,并使他们改变的原因仅取决于他们做的一件事,对我而言,这是SRP的重点.