2008-09-24 1 views
6

This question about unit testing best practices упоминает классы проектирования для инъекций зависимости. Это заставило меня задуматься о том, что именно это может означать.Рекомендации по проектированию классов для инъекций зависимостей

Только что начал работать с инверсией контрольных контейнеров. У меня есть некоторые идеи по этому вопросу, поэтому позвольте мне бросить их к стене и посмотреть, какие палки.

Как я вижу это, существуют три основных типа зависимостей, которые может иметь объект.

  1. Зависимость от объекта - Реальный объект, который будет использоваться данным классом. Например, LogInVerifier в LogInFormController. Они должны вводиться через конструктор. Если класс достаточно высокий, что требует более 4 из этих объектов в конструкторе, подумайте о его разломе или, по крайней мере, с использованием заводского шаблона. Вы также должны рассмотреть возможность обеспечения зависимости интерфейса и кодирования с интерфейсом.
  2. Простая настройка - Например, пороговое значение или период ожидания. Как правило, они должны иметь значение по умолчанию и устанавливаться через построитель фабричного шаблона. Вы также можете предоставить перегрузки конструктора, которые их устанавливают. Однако в большинстве случаев вы, вероятно, не должны заставлять клиента настраивать его явно.
  3. Объект сообщения - Объект, передаваемый из одного класса в другой, который, по-видимому, использует принимающий класс для бизнес-логики. Примером может служить объект User для класса LogInCompleRouter. Здесь я нахожу, что часто бывает лучше, чтобы сообщение не указывалось в конструкторе, так как вам пришлось бы либо зарегистрировать экземпляр пользователя с контейнером IoC (делая его глобальным), либо не создавать экземпляр LogInCompleteRouter до тех пор, пока у вас не появится экземпляр пользователя (для которых вы не могли использовать DI или, по крайней мере, нуждались бы в явной зависимости от контейнера). В этом случае было бы лучше передать объект сообщения только тогда, когда вам это нужно для вызова метода (например, LoginInCompleteRouter.Route (User u);).

Кроме того, я должен отметить, что не все должно быть DI'ed, если у вас есть простой немного функциональности, которая была просто удобно факторизовать к классу одноразовая, это, вероятно, хорошо, чтобы создать экземпляр на месте. Очевидно, это призыв к суду; если я счел целесообразным написать класс, такой как

class PasswordEqualsVerifier { 
    public bool Check(string input, string actual) { return input===actual;} 
} 

я, вероятно, не буду беспокоить зависимость впрыскивания и буду просто объект его экземпляр непосредственно внутри с помощью блока. Следствием является то, что, если стоит писать модульные тесты, то, вероятно, стоит впрыскивать.

Так что вы, ребята, думаете? Любые дополнительные рекомендации или противоположные мнения приветствуются.

ответ

1

Важно, чтобы попытаться кодировать интерфейсы и заставить классы использовать экземпляры этих интерфейсов, а не создавать сами экземпляры. Вы, очевидно, можете сходить с ума, но это общая хорошая практика, независимо от модульного тестирования или DI.

Например, если у вас есть объект доступа к данным, вы можете быть склонны написать базу для всех DAO, как это:

public class BaseDAO 
{ 
    public BaseDAO(String connectionURL, 
        String driverName, 
        String username, String password) 
    { 
     // use them to create a connection via JDBC, e.g. 
    } 

    protected Connection getConnection() { return connection; } 
} 

Однако, было бы лучше, чтобы удалить это из класса в пользу интерфейса

public interface DatabaseConnection 
{ 
    Connection getConnection(); 
} 

public class BaseDAO 
{ 
    public BaseDAO(DatabaseConnection dbConnection) 
    { 
     this.dbConnection = dbConnection; 
    } 

    protected Connection getConnection() { return dbConnection.getConnection(); } 
} 

Теперь вы можете предоставить multilple imlementations из DatabaseConnection. Даже игнорируя модульное тестирование, если мы предполагаем, что мы используем JDBC, есть два способа получить Connection: пул соединений из контейнера или напрямую с помощью драйвера. Теперь ваш код DAO не связан ни с одной из стратегий.

Для тестирования вы можете сделать MockDatabaseConnection, который подключается к встроенной реализации JDBC с помощью консервированных данных для проверки вашего кода.