单一责任原则正确的方法

时间:2015-10-08 08:39:47

标签: oop solid-principles

SRP真的让我烦恼。我知道如何找到责任我不知道如何正确组装它们 e.g

class Modem{
  public void dial(){//code here}
  public void hangup(){//code here}
  public void send(){//code here}
  public void recive(){//code here}
}

在这个常见的例子中,我们有连接和沟通的责任。所以我们把它分成2个新接口

interface Connection{ 
  public void dial();
  public void hangup();
}

interface Communication{ 
  public void send();
  public void recive();
}

实施它们:

class SimpleModemConnection implements Connection{ 
  public void dial(){//code here}
  public void hangup(){//code here}
}

class SimpleModemCommunication implements Communication{ 
  public void send(){//code here}
  public void recive(){//code here}
}

此时我真的不知道客户端代码应该是什么样子

我是否将这些接口聚合到Modem类中?

class Modem {
 Connection connection = new SimpleModemConnection();
 Communication communication = new SimpleModemCommunication(); 
}

main(){
 Modem modem = new Modem();
 modem.connection.dial();
 modem.communication.send();
 modem.communication.recive();
 modem.connection.hangup();
}

我是否直接使用它们

main(){
 Connection connection = new SimpleModemConnection();
 Communication communication = new SimpleModemCommunication(); 
 connection.dial();
 communication.send();
 communication.recive();
 connection.hangup();
}

或者还有其他方法吗?

2 个答案:

答案 0 :(得分:1)

恐怕你可能会过度思考这个问题。调制解调器需要连接和通信。除非你知道并期望这两者可以分开的情况,否则就没有必要将它分开。最后,这些原则不应成为您设计的主要推动力。这应该是您对域的了解以及您期望在系统中进行的更改。

那么您需要回答的是,您的调制解调器类是否需要更换其连接/通信子系统?

答案 1 :(得分:0)

有时这可能会让人感到困惑。我每天都在努力解决同样的问题,但你想一想就好了。我一直在积极寻求使用SOLID原则以及我的TDD实践。您似乎没有想到的一件事是谁将在代码中使用您的调制解调器,单元测试和实际对象用户。

在我看来,它就是这样的。调制解调器负责拨号,挂断,发送和接收数据,因此这些是向您的API用户公开的功能(接收除外),无论是您的单元测试还是您的代码用户。因此,存在以下内容。

<强> IModem.cs

interface IModem
{
  public bool Connect(); // Seen in your code as dial
  public void Disconnect(); // Seen in your code as hangup
  public void SendData(); // Take data as parameter
  // Receive will not be public, instead I would make it call out to the user saying "I have received data for you"
}

这清楚地表明调制解调器对象的责任是将数据连接,断开连接并发送到需要的位置。现在调制解调器是否进行连接和通信是另一个问题。我会说你使用SimpleConnection和SimpleCommunication模块的东西是完美的(我会稍微改变命名;))。连接变为IConnectionModule,通信变为ICommunicationModule,以及一些功能名称更改。拨号连接,挂断到断开连接并发送到SendData。考虑到这一点,我采取以下方法。

我的调制解调器的责任:我的调制解调器将使用它拥有的模块将用户连接到远程主机,以及断开与主机的连接或发送任何数据必要。 然后上面的定义产生以下代码。

<强> Modem.cs

class Modem : IModem
{
  private IConnectionModule _connectionModule;
  private ICommunicationModule _communicationModule;

  public Modem(IConnectionModule connectionModule, ICommunicationModule communicationModule)
  {
    _connectionModule = connectionModule;
    _communicationModule = communicationModule;
  }

  public bool Connect()
  {
    bool connectionSuccess = _connectionModule.Connect()
    return connectionSuccess;
  }

  public void Disconnect()
  {
    _connectionModule.Disconnect();
  }

  public void SendData()
  {
    _communicationModule.SendData();
  }
}

考虑上述情况,您可以按如下方式列出职责:

调制解调器:用作API用户之间的桥梁,允许用户发送和接收信息。

连接模块:将调制解调器连接到主机(用户永远不会使用它,唯一的用户就是它的单元测试套件和调制解调器)

通讯模块:向已连接的主机发送信息(用户永远不会使用此功能,唯一使用此功能的用户将是它的单元测试套件和调制解调器)

将模块“隐藏”给用户的原因是调制解调器的用户不必知道正在使用哪个连接模块。您所要做的就是调用Connect / Disconnect,并提供功能。其余的都应该是“看不见的”。同样,这完全取决于您的开发风格,但我总是尽量保持良好的分离,并确保每次调用始终有一个动作。无论是养殖到不同的对象还是在课堂内完成。

我希望这有帮助,让我知道你的想法,我总是在讨论设计和SOLID原则。