N-уровневая архитектура - структура с несколькими проектами в VB.NET - PullRequest
7 голосов
/ 18 марта 2010

Я хотел бы получить несколько советов о том, как лучше всего использовать в следующей ситуации ...

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

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

Проекты:

MyCompany.Common.dll - содержит интерфейсы, все другие проекты имеют ссылку на этот.
MyCompany.Windows.dll - проект Windows Forms, ссылки на MyCompany.Business.dll
MyCompany.Web.dll - Проект веб-сайта, ссылки на MyCompany.Business.dll
MyCompany.Busniess.dll - бизнес-уровень, ссылается на MyCompany.Data. * (Во время выполнения)
MyCompany.Data.AccountingSys1.dll - Уровень данных для системы учета 1 MyCompany.Data.AccountingSys2.dll - Уровень данных для системы учета 2

Проект MyCompany.Common.dll будет содержать все интерфейсы, каждый проект будет иметь ссылку на этот.

Public Interface ICompany
    ReadOnly Property Id() as Integer
    Property Name() as String
    Sub Save()
End Interface

Public Interface ICompanyFactory
    Function CreateCompany() as ICompany
End Interface

Проект MyCompany.Data.AccountingSys1.dll и MyCompany.Data.AccountingSys2.dll будет содержать классы, подобные следующим:

Public Class Company
    Implements ICompany

    Protected _id As Integer
    Protected _name As String

    Public ReadOnly Property Id As Integer Implements MyCompany.Common.ICompany.Id
        Get
            Return _id
        End Get
    End Property

    Public Property Name As String Implements MyCompany.Common.ICompany.Name
        Get
            Return _name
        End Get
        Set(ByVal value as String)
            _name = value
        End Set
    End Property

    Public Sub Save() Implements MyCompany.Common.ICompany.Save
        Throw New NotImplementedException()
    End Sub

End Class

Public Class CompanyFactory
    Implements ICompanyFactory

    Public Function CreateCompany() As ICompany Implements MyCompany.Common.ICompanyFactory.CreateCompany
        Return New Company()
    End Function

End Class

Проект MyCompany.Business.dll будет предоставлять бизнес-правила и извлекать данные из слоя данных:

Public Class Companies

    Public Shared Function CreateCompany() As ICompany
        Dim factory as New MyCompany.Data.CompanyFactory
        Return factory.CreateCompany()
    End Function    

End Class

Любые мнения / предложения будут с благодарностью.

Ответы [ 3 ]

5 голосов
/ 18 марта 2010

Несколько комментариев.

Я бы избегал сборки MyCompany.Common.dll. Как правило, они заполняются всевозможными несвязанными вещами, которые затем часто меняются, требуя перестройки всех ваших сборок.

Я бы назвал ваши сборки именем приложения, а также названием компании. MyCompany.MyApplication.Business.dll предпочтительнее MyCompany.Business.dll. Тогда легче разделить приложения на части и повторно использовать код из нескольких приложений.

Лучше всего иметь отдельные контрактные сборки для каждого типа сборки реализации, которую вы собираетесь иметь. В вашем случае я бы предложил следующее:

MyCompany.MyApplication.Windows-Contract.dll
MyCompany.MyApplication.Windows.dll

MyCompany.MyApplication.Web-Contract.dll
MyCompany.MyApplication.Web.dll

MyCompany.MyApplication.Business-Contract.dll
MyCompany.MyApplication.Business.dll

MyCompany.MyApplication.Data-Contract.dll
MyCompany.MyApplication.Data.AccountingSys1.dll
MyCompany.MyApplication.Data.AccountingSys2.dll

Из вашего описания видно, что сборки AccountingSys1 и AccountingSys2 имеют общий контракт, следовательно, только одна контрактная сборка для двух сборок реализации.

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

При настройке ссылок на сборки вы должны убедиться, что сборки когда-либо ссылаются только на контрактные сборки, например:

Data.AccountingSys1
    Data-Contract

Data.AccountingSys2
    Data-Contract

Business
    Business-Contract
    Data-Contract

Windows
    Windows-Contract
    Business-Contract
    Data-Contract (maybe)

Web
    Web-Contract
    Business-Contract
    Data-Contract (maybe)

В результате сборки реализации никогда не зависят от других сборок реализации. При изменении реализации у вас есть только одна сборка для восстановления.

Исключением из этого правила является создание иерархий наследования. Например, вы можете создать *.Data.AccountingSys.dll для определения базовых классов для двух конкретных сборок системы учета.

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

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

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

1 голос
/ 18 марта 2010

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

1 голос
/ 18 марта 2010

Ваш общий подход звучит :)

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...