Первый вопрос, который нужно задать себе, это что такое GeoData? Другими словами, какова ответственность класса?
Похоже, что он является частью Доменного уровня и может содержать бизнес-логику. Может использоваться ( в сочетании с) другими классами.
Если это так, каковы зависимости? Один из способов определить это - попытаться написать модульных тестов , которые тестируют GeoData изолированно. Если тестирование требует значительных настроек, тестируемый класс либо тесно связан с другими классами, либо имеет несколько обязанностей (низкая сплоченность ).
Допустим, мы изменили класс так, чтобы конструктор принял параметр строки соединения. Как мы можем протестировать публичный метод GetCountries? Что ж, сначала мы создали базу данных с известными тестовыми данными ...
Это отнимает много времени и хрупок (что, если кто-то обновит данные?), И тест будет выполняться относительно медленно (он должен подключиться к базе данных).
Ну, мы могли бы передать объект, реализующий IDbConnection, конструктору (внедрение конструктора). Обратите внимание, что внедрение зависимостей обычно включает передачу интерфейсов или абстрактных классов. Чтобы проверить это, нам нужно создать поддельный IDbConnection. Мы могли бы использовать изолирующую (насмешливую) структуру . Но тогда нам понадобится создать поддельный IDbCommand при вызове CreateCommand ...
Цитируя Джереми Миллера (автора StructureMap ): «Это слишком много усилий для слишком маленькой выгоды». См. Его статью Лучшие и худшие практики для фиктивных объектов .
Одна из возможностей - использовать Шаблон репозитория . Вы должны передать интерфейс к конкретному репозиторию в конструктор GeoData. Это было бы легко подделать (вручную или с насмешливой библиотекой) для тестирования. Конкретный репозиторий будет обрабатывать все данные доступа. Его можно комбинировать с каркасом ORM для дальнейшего абстрагирования доступа к данным. Управление строкой соединения будет осуществляться через ORM или через репозиторий (предпочтительно в другой зависимости или базовом классе).
Если это звучит сложно, потому что это так. Вы выбрали один из самых сложных случаев для внедрения зависимостей (который, к сожалению, также является одним из самых распространенных).
Внедрение зависимости само по себе является довольно простой концепцией. Если ваш класс вызывает веб-службу, вы можете поместить код веб-службы в отдельный класс, который больше ничего не делает, реализовать интерфейс и передать этот интерфейс вашему исходному классу. Контейнерные структуры DI / IoC могут сделать это проще, если у вас много классов и / или зависимостей, но они не являются обязательными.
РЕДАКТИРОВАТЬ: Просто чтобы быть ясно, Внедрение зависимости не сложная часть. Разделение доступа к данным.