N层架构 - VB.NET中具有多个项目的结构

时间:2010-03-17 22:15:09

标签: vb.net architecture n-tier-architecture

我想就以下情况下使用的最佳方法提出一些建议......

我将拥有一个Windows应用程序和一个Web应用程序(表示层),这些都将访问一个公共业务层。业务层将查看配置文件以查找将在运行时创建引用的dll(数据层)的名称(这是最好的方法吗?)。

在运行时向数据访问层创建引用的原因是,应用程序将根据客户端使用的内容与不同的第三方记帐系统进行交互。所以我会有一个单独的数据访问层来支持每个会计系统。这些可能是单独的安装项目,每个客户端都会使用其中一个,他们不需要在两者之间切换。

项目:

MyCompany.Common.dll - 包含接口,所有其他项目都引用此接口。
MyCompany.Windows.dll - Windows窗体项目,引用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 个答案:

答案 0 :(得分:5)

一些评论。

我会避免举行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

根据您的描述,AccountingSys1AccountingSys2程序集似乎共享一个共同的合同,因此只有一个合同程序集用于两个实现程序集。

合同装配应代表您的设计,而不是您的实施,并且只能因设计变更而改变。您应该避免使用任何“重要”代码(以避免错误),并且应该将代码限制为接口,枚举,异常,属性,事件参数和结构 - 所有这些都没有“重要”代码。

设置程序集引用时,应确保程序集仅引用合同程序集,如下所示:

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 :(得分:1)

你的一般方法是合理的:)

您可以考虑将所有接口放在一个单独的程序集(dll)中(严格来说,接口位于业务逻辑和数据访问实现之间 - 它们应该是唯一可以访问接口的东西),但是在宏伟的计划可能不是什么大不了的事。

就个人而言,我有一个返回对象的共享工厂方法,并在使用时正确地投射它。

答案 2 :(得分:1)

这是一个很好的方法!我已经在我们的一个系统中使用它,它已被证明是可靠的,东部维护,并允许我们在需要时快速添加额外的接口(例如,当我们需要与我们获得的公司的另一个会计系统接口时。 )