3

Я новичок в насмешливости и зависимости, и вам нужно руководствоваться.Rhino Mocks, инъекция зависимостей и разделение проблем

Мое приложение использует типичную архитектуру N-уровня, где BLL ссылается на DAL, а пользовательский интерфейс ссылается на BLL, но не на DAL. Довольно прямо.

Позволяет сказать, к примеру, у меня есть следующие классы:

class MyDataAccess : IMyDataAccess {} 
class MyBusinessLogic {} 

Каждый существует в отдельной сборке.

Я хочу высмеять MyDataAccess в тестах для MyBusinessLogic. Поэтому я добавил конструктор класса MyBusinessLogic, чтобы принять параметр IMyDataAccess для инъекции зависимостей. Но теперь, когда я пытаюсь создать экземпляр MyBusinessLogic на уровне пользовательского интерфейса, он требует ссылки на DAL.

Я думал, что могу определить конструктор по умолчанию в MyBusinessLogic, чтобы установить стандартную реализацию IMyDataAccess, но не только это похоже на кодовое хранилище, на самом деле это не решило проблему. У меня все равно будет публичный конструктор с IMyDataAccess в подписи. Таким образом, слой UI по-прежнему требует ссылки на DAL для компиляции.

Одним из возможных решений, с которым я сталкиваюсь, является создание внутреннего конструктора для MyBusinessLogic с параметром IMyDataAccess. Затем я могу использовать Accessor из тестового проекта для вызова конструктора. Но есть еще этот запах.

Какое здесь общее решение. Я просто должен делать что-то неправильно. Как я могу улучшить архитектуру?

ответ

4

Вы можете определить свои классы, как это:

public class MainForm : Form 
{ 
    private readonly businessLogic; 

    public MainForm(IBusinessLogic businessLogic) 
    { 
     this.businessLogic = businessLogic; 
    } 
} 

public class BusinessLogic : IBusinessLogic 
{ 
    private IDataLayer dataLayer; 

    public BusinessLogic(IDataLayer dataLayer) 
    { 
     this.dataLayer = dataLayer; 
    } 
} 

public class DataLayer : IDataLayer 
{ 
    public DataLayer(string connectionString) 
    { 
    } 
} 

Обратите внимание, как основная форма не знает о DAL здесь. Теперь нам нужен фрагмент кода, который знает все классы, так что они могут быть связаны друг с другом. Обычно это делается в начале приложения:

public static void Main(string[] args) 
{ 
    var dataLayer = new DataLayer("foo"); 
    var businessLogic = new BusinessLogic(dataLayer); 
    var mainForm = new MainForm(businessLogic); 

    Application.Run(mainForm); 
} 

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

Примеры рамок для инъекций зависимостей для .NET: AutoFac, Castle, Spring.NET, StructureMap, Ninject и Managed Extensibility Framework.

+0

Как использование емкости IoC влияет на производительность? Мне очень нравится это решение, и я сейчас играю с Castle. – mikesigs

+0

@whatispunk: Использование контейнера IoC не влияет на производительность после запуска. Если время запуска увеличивается слишком долго из-за количества подключаемых объектов, обычно у вас есть средства в контейнере для обеспечения ленивой загрузки (например, 'System.Lazy ' для управляемой инфраструктуры расширяемости). –

+0

Делает смысл. И в моем случае я работаю над веб-приложением, поэтому время запуска не имеет большого значения. Спасибо за вашу помощь. – mikesigs

2

I answered вопрос вчера о том, как structure a .NET solution, который, я думаю, решит вашу проблему.

Ключевым моментом для вас в моем ответе должно быть то, что ни одна из сборников «реализации» не имеет ссылок на другие сборки «реализации». Это должно решить проблему разделения проблем.

Кроме того, структура также почти предусматривает использование инъекции зависимостей, и она очень хорошо подходит для модульного тестирования и использования насмешек.

Надеюсь, это поможет.

+0

Это походит на действительно отличное решение, но я думаю, что это была бы настоящая борьба, чтобы убедить остальную часть моей команды перестроить все наше приложение. – mikesigs

0

Если вы хотите избежать ссылки на dll доступа к данным из dll UI, то вы можете извлечь интерфейсы доступа к данным/базовые классы в третью библиотеку и иметь две другие ссылки.