2015-10-08 6 views
1

SRP действительно ошибка. Я знаю, как найти себя ответственность, что я не знаю, как правильно напримерОдиночная ответственность Принцип правильного подхода

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} 
} 

и в этот момент я действительно не знаю, как клиентский код должен выглядеть

ли я агрегировать эти intefaces в модем класс ?

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(); 
} 

Или есть какой-то другой способ делать?

+0

Вы можете сделать то и другое. Но что лучше в ВАШЕМ мнении? Я бы предложил использовать первое решение, чтобы обернуть их внутри класса модема – MajkeloDev

+1

@MajkeloDev Спасибо за ваш повтор, но теперь я не понимаю, как класс модема wraping Интерфейсы связи и подключения отличаются от оригинального класса модема в перспективе SPR? – vilshadov

ответ

0

Это может быть очень запутанным несколько раз. Я ежедневно борюсь с одними и теми же вопросами, но хорошо, что вы об этом думаете. Я активно занимаюсь использованием принципов SOLID вместе с моей практикой TDD. Одна вещь, которая кажется, что вы не думаете о том, кто будет использовать ваш модем, модульные тесты и фактических пользователей объектов в коде.

В моем сознании это работает так. Модем несет ответственность за набор, вешение, отправку и получение данных, так что это функции, открытые пользователю вашего API (за исключением Receive), будь то ваши модульные тесты или ваш пользователь кода. Поэтому существовало бы следующее.

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" 
} 

Это четко указано, что ответственность вашего модема объекта является Connect, Disconnect и передачи данных, где она должна идти. Теперь, является ли модем соединением и коммуникацией другой вопрос. Я бы сказал, что то, что у вас есть с модулями SimpleConnection и SimpleCommunication, идеально (я бы немного изменил наименование)). Соединение становится IConnectionModule и Communication становится 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.

+0

Вы правы Я не думал о том, кто будет использовать мой код, кто будет аудиторией для класса модемов, и это полезно. Также neme для интерфейсов реализации класса. Соединение и связь должны указывать на конкретный битрейт модема, например V92ModemConnection. Я не понимаю, почему вы создали интерфейс IModem? isnt это эквивалент Модем реализует соединение, связь? И почему вы используете префикс I в соглашении об именовании интерфейса? это oldfashion? – vilshadov

+0

@vilshadov Я - конвенция .NET. 'IModem' будет необходимо, только если вы планируете использовать несколько модемов. Возможно, маловероятно, если большинство деталей реализации уже охвачены стратегиями инъекций (ConnectionStrategy, CommunicationStrategy). Даже для модульного тестирования лучше протестировать реальный код, чем при необходимости. Кстати, «Модуль» - это плохой выбор имени, и если вы хотите добавить какое-то значение «Стратегия», лучше, так как все знают, что такое шаблон стратегии. – plalx

+0

Я не согласен полностью с @plalx, ​​говорящим, что IModem будет полезен только в том случае, если вы планируете иметь несколько реализаций. При использовании DI я обнаружил, что «проще» вводить интерфейсы вместо реализаций, сохраняя скрытые внутренние детали. И я не считаю, что все знают стратегию, но все должны. Я использовал модуль из-за отношения, которое он имеет к сетевому оборудованию. Личное предпочтение наименования, я думаю, мы все имеем их. С моей стороны стратегия в конце - это то, что я никогда не использовал даже при использовании шаблона стратегии. Мне нравятся конкретные имена домена. –

0

Я боюсь, что вы можете переусердствовать. Модем должен подключаться и общаться. Если вы не знаете и не ожидаете ситуации, когда эти два могут быть отделены, просто нет смысла раскалывать это. В конце концов, эти принципы не должны быть основной движущей силой вашего дизайна. Это должно быть ваше знание домена и тех изменений, которые вы ожидаете в системе.

Итак, что вам нужно ответить, если ваш класс модема когда-либо понадобится для замены подсистемы связи/связи?