2011-01-25 4 views
2

У меня есть веб-приложение .net, которое я взял на себя, которое в прошлом страдал от того, что вся бизнес-логика находилась в коде за страницами и очень привязана к пользовательскому интерфейсу..NET Application Architecture - что является оптимальной сборкой для этого класса?

Я потратил некоторое время на рефакторинг, в частности, на переход кода доступа к данным в специальный проект доступа к данным «Company.DataAccess» (например). Другие логические части кода также имеют свои собственные сборки.

То, что я не устраивает, является размещение объектов, которые должны быть общими для всех сборок:

К примеру - В моем проекте «Company.ClientDataImport», у меня есть классы, содержащие бизнес-логику для импорт данных клиента.

Один конкретный элемент функциональности, содержащий этот код, заключается в том, что формат импорта клиента можно сопоставить с нашим стандартным форматом импорта. Итак, у меня есть класс «DataImportFieldMappingInfo» в сборке «Company.ClientDataImport»:

public class DataImportFieldMappingInfo { 

    int CompanyFieldName 
    { 
     get; 
     set; 
    } 

    int ClientFieldName 
    { 
     get; 
     set; 
    } 
} 

Эти отображения сохраняются в базе данных, поэтому в какой-то момент, мне нужно, чтобы заполнить коллекцию с экземплярами этого объекта.

Одной из целей архитектуры является то, что вся база данных IO должна обрабатываться компанией «Company.DataAccess».

Я хочу, чтобы «Company.DataAccess» знала класс DataImportFieldMappingInfo, чтобы он мог использовать класс, предназначенный для хранения этого типа данных, но это означает, что «Company.DataAccess» и «Company.ClientDataImport» оба должны знать DataImportFieldMappingInfo, чтобы они могли общаться с использованием одних и тех же классов.

Моим решением этой общей проблемы до сих пор является использование другой библиотеки под названием «Company.DomainEntities», которая содержит классы для объектов, которые совместно используются в других сборках в приложении. Это хорошо работает, и все сборки могут общаться в терминах одних и тех же объектов. Классы действительно просто содержат свойства, поэтому они представляют собой только контейнеры данных, а не содержащие логику приложения.

Что мне не нравится в этом, так это то, что DataImportFieldMappingInfo является проблемой импорта данных, и поэтому я считаю, что это должно быть в этом пространстве имен и, следовательно, в проекте «Company.ClientDataImport». Ограничения ссылочной ссылки препятствуют этому, поэтому я должен использовать проект «Company.DomainEntities» как средний человек.

С моей архитектурой что-то не так, или это обычная практика в такой ситуации?

ответ

2

Я склонен согласиться с Марком; но есть пара других вещей, которые вы могли бы подумать:

Что представляет собой «бизнес-логика» против кода «Доступ к данным» и простые структуры данных, о которых вы «знаете» приложение? На первый взгляд DataImportFieldMappingInfo выглядит так, как будто это был доступ к данным, но я думаю, что они на самом деле просто общие структуры (и более ориентированы на бизнес), поэтому использование их в общей сборке имеет смысл - если вы используете их для обмена данными между разными слоями/assembilies.

Другой вид принять, что все хранилищ данных (который включает в себя базы данных, специфичные для вашего приложения, а также все внешние источники данных, такие как внешние базы данных, файлы или системы), рассматриваются в равной степени и доступны через interface - не через единую конкретную реализацию. В этом случае все данные указываются в центре бизнес-логики/домена по центру, а не в конкретном способе доступа к данным/хранилища. В этом случае вы также определяете все общие структуры данных, используемые вашим приложением в общей сборке.

Edit:

Короче говоря, интерфейсы позволяют абстрагировать из сложности и зависимостей, связанных с неприятными вещами, которые вы не хотите быть тесно (и постоянно), связанными с.

Принцип использования интерфейсов: Dependency Inversion (DI). (Нет никакой информации об этом - на самом деле вы можете найти слишком). DI идет по пути, помогая создавать системы, которые хорошо играют с Stable Dependencies Principle.

Идея состоит в том, что вместо того, чтобы ваша бизнес-логика (сборка/сбор) зависела от доступа к данным, у вас есть оба они зависят от интерфейса; вы можете в любое время поменять местами реализации. У вас может быть «реальный» компонент Data Access, который работает против SQL и «фиктивный», который возвращает фиктивные данные теста прямо из вашего кода.

При проектировании интерфейса идея состоит в том, чтобы проектировать его с точки зрения бизнес-логики/домена - а не технического; хотя есть случаи, когда это уместно. Задача реализации (то есть: класс доступа к данным, который реализует интерфейс) заключается в переводе между интерфейсом, ориентированным на бизнес, и любым странным источником данных, с которым он имеет дело. Например, ваш средний поставщик данных на базе SQL может высасывать данные через DataReader и конвертировать в MyBusiness.Common.Info.OutstandingAccountsCollection.

Код Структура

  • Общее собрание (MyBusiness.Common) - содержит любые структуры данных, которые используются для обмена данных между вашими слоями (например: в MyBusiness.Common.Info.OutstandingAccount и MyBusiness.Common.Info.OutstandingAccountCollection классов).
  • Интерфейсные ассембли: у вас может быть несколько таких. Если весь доступ к данным осуществляется через одну систему (скажем, SQL), то у вас, вероятно, будет только один (MyBusiness.Interfaces.DataAccessProvider), но если у вас есть различные системы для взаимодействия, вы хотите сохранить их отдельно. MyBusiness.Interfaces.DataAccessProvider ссылается на общую сборку, потому что она будет включать типы «info» в своих контрактах.
  • Конкретные узлы доступа к данным: (MyBusiness.DataAccess.SQLDataAccessProvider). это ссылается на сборку Common и Interface.
  • В вашей бизнес-логике (MyBusiness.BusinessLogic) указаны общие и интерфейсные сборки.

Для получения дополнительной информации (и диаграмм) проверить эту часть (само оповещение продвижения): 5-Layer Architecture

+0

Не могли бы вы расширить идею интерфейса? Я понимаю интерфейсы, но я не уверен, как я могу применить его в этой ситуации. – gb2d

+0

Отлично, спасибо. – gb2d

2

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

Другой подход, не неслыханный, состоит в том, чтобы просто сказать, что «все эти сборки не делают ничего лишнего» и просто используют пространства имен для разделения кода. Если вы не нуждаетесь в, чтобы иметь возможность работать только с подмножеством dlls, почему бы не просто один dll? Классический контрапункт к этому - это то, где у вас есть несколько разных пользовательских интерфейсов/сервисов, которые потребляют одну и ту же DLL (или разные подмножества DLL).

+0

Это дает мне уверенность в том, что я не принял плохой подход к этому. Ваш второй подход также заставил меня задуматься. Оглядываясь на мои сборки, кажется, что иногда разделение проекта необходимо для повторного использования, но не всегда. Я бы не рассматривал разделение кода по папкам/пространствам имен, а не по проектам, которые можно использовать. Одна из причин, по которой я стремился установить четкое разделение логики в приложении, заключается в том, что она делает некоторые из плохой практики, которые я видел в этом проекте, сложнее продолжать, например, проходить классы страниц по всему месту (ASP.NET формы). – gb2d

Смежные вопросы