2010-03-17 76 views
7

多个项目的结构,我想在下列情况下使用的最佳方法一些建议......N层体系结构 - 在VB.NET

我将有一个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.dllMyCompany.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 

任何意见/建议将不胜感激。

回答

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框架或创建第三组包含您的工厂方法的组件。

这种结构的另一个好处是单元测试更简单,可以基于合同而不是实现,从而帮助您编写干净,可测试的代码。

这可能看起来像很多程序集,但是通过保持代码不会产生讨厌的依赖关系可以获得的好处将显着降低您的项目变得过于复杂的可能性,并有助于提高您的质量。现在有点疼痛会在以后消除这么多痛苦。

+0

我会试试看,谢谢。 – 2010-03-18 22:04:47

+0

+1你忘了提及一段时间后''Common' lib的一半也会被废弃,没有人会解开它。您可能也有兴趣的想法(主要在我的意见IMNSHO)在http://stackoverflow.com/questions/925453/wcf-service-proxy-name-namespace-naming-strategy/2430056#2430056 – 2010-03-19 08:48:35

+0

+1谢谢!我们只是实施了类似的东西,很好地看到其他人已经思考过,并像我们一样来到相同的结构。 – 2010-05-02 01:19:12

1

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

你可以考虑把所有的接口在一个单独的组件(DLL)(严格地说接口的业务逻辑和数据访问实现之间坐镇 - 他们应该是唯一的可以访问界面的东西),但是在可能不是什么大问题的宏伟计划中。

就我个人而言,我会有一个共享工厂方法返回一个对象,并在使用时恰当地转换它。

+0

如果我在数据层和业务层之间的独立程序集中有接口,表示层如何访问从业务层返回的公司对象的属性。 例如(来自表示层): Dim company As ICompany = MyCompany.Business.Companies。CreateCompany() 为了在Presentation Layer中工作,需要引用位于Interface组件中的ICompany接口类。 有没有另一种方法来做到这一点? – 2010-03-18 01:15:44

+0

focus.nz - 看看我的答案,因为我想我在那里解释它。 http://stackoverflow.com/questions/2466293/n-tier-architecture-structure-with-multiple-projects-in-vb-net/2467026#2467026 – Enigmativity 2010-03-18 02:06:08

+0

@ focus.nz - 界面的定义没有与其使用的实体/类型的定义处于相同的位置,您可以将这些定位在不同的(中心)位置(因此可见性)。它还取决于您是否想要在DAL和BL之间以及BL和UI之间使用相同的类型(例如)。 – 2010-03-18 19:21:30

1

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