2013-01-01 80 views
7

请参阅下面的代码:打破BLL(业务逻辑层)到BLL和DAL(数据访问层)

Imports Microsoft.VisualBasic 

Public Class PersonBLL 
    Private Name As String 
    Private Age As Integer 

    Dim objPersonDAL As New PersonDAL 
    Dim objPerson As Person 

    Public Sub getPersonByID() 
     objPerson = objPersonDAL.getPersonByID() 
     MsgBox(objPerson.Name) 
    End Sub 
End Class 

Public Class PersonDAL 
    Private Name As String 
    Private Age As Integer 

    Public Function getPersonByID() As Person 
     'Connect to database and get Person. Return a person object 
     Dim p1 As New Person 
     p1.Name = "Ian" 
     p1.Age = 30 
     Return p1 
    End Function 
End Class 

Public Class Person 
    Private _Name As String 
    Private _Age As Integer 

    Public Property Name() As String 
     Get 
      Return _Name 
     End Get 
     Set(ByVal value As String) 
      _Name = value 
     End Set 
    End Property 

    Public Property Age() As Integer 
     Get 
      Return _Age 
     End Get 
     Set(ByVal value As Integer) 
      _Age = value 
     End Set 
    End Property 
End Class 

PersonBLL调用PersonDAL并返回一个Person对象。这是正确的方法吗?即我已经识别出一个持久类,并用一个函数来创建一个相应的DAL类,以访问数据并返回Person对象。

有一条评论指出这个问题是“主观的”。我同意这一点。我意识到设计取决于项目的要求。有没有为设计类似于SOLID(单一职责等)的DAL而记录的原则等。

+0

“正确的方法”有点主观。 “这是一种有效的方法吗?”是可以回答的 - 我会说“是”。 – David

+0

@David Stratton,我已经更新了这个问题。你是否知道像设计数据访问层特别相关的SOLID等原理? – w0051977

+0

很好的编辑。我会让聪明的人比我回答这个问题。这不是我的专业领域,大多数人在这个网站上比我更聪明。我可能会误导你。我所要提供的就是我之前看过这种设计,来自非.NET背景的人 - 这似乎很常见。我个人觉得这很乏味,但就像我说的,我不是这个街区最聪明的人。 – David

回答

6

是的,您的问题演示了一种非常干净的方法来将逻辑分为多个层。 PersonBLL类将成为业务层的一部分,PersonDAL类将成为数据访问层的一部分,Person类将成为数据传输对象(DTO)层的一部分。这是分开你的图层的一种非常常见的方式,在许多情况下都能很好地工作。

我唯一的建议是:

  • 你应该把每一层在自己的命名空间,如果还没有自己的类库项目。
  • 您不应该从业务层显示消息框。我以为你只是以此作为示范的手段,但为了以防万一,我想我应该提及它。显示消息框应该是UI层的一部分。例如,如果您从Windows服务或Web服务调用PersonBLL.getPersonByID,则显示消息框完全不合适。
  • 通常,所有方法都是PascalCase,而不是camelCase。有些人更喜欢使用私人方法骆驼案件,但肯定公共方法不应该是骆驼案件。
  • 考虑使用依赖注入技术(DI)将数据访问对象注入业务对象。

依赖注入

这里有一个如何与DI技术做一个这样的例子:这样做,这样有很多好处

Public Class BusinessFactory 
    Public Function NewPersonBusiness() As IPersonBusiness 
     Return New PersonBusiness(New PersonDataAccess()) 
    End Function 
End Class 

Public Class PersonBusiness 
    Implements IPersonBusiness 

    Public Sub New(personDataAccess As IPersonDataAccess) 
     _personDataAccess = personDataAccess 
    End Sub 

    Private _personDataAccess As IPersonDataAccess 

    Public Function GetPersonByID() As PersonDto Implements IPersonBusiness.GetPersonByID 
     Return _personDataAccess.GetPersonByID() 
    End Sub 
End Class 

Public Interface IPersonBusiness 
    Function GetPersonByID() As PersonDto 
End Interface 

Public Interface IPersonDataAccess 
    Function GetPersonById() As PersonDto 
End Interface 

Public Class PersonDto 
    Private _name As String 
    Private _age As Integer 

    Public Property Name() As String 
     Get 
      Return _name 
     End Get 
     Set(ByVal value As String) 
      _name = value 
     End Set 
    End Property 

    Public Property Age() As Integer 
     Get 
      Return _age 
     End Get 
     Set(ByVal value As Integer) 
      _age = value 
     End Set 
    End Property 
End Class 

。你可以有多个可互换的数据访问层实现,所以它更加灵活。此外,您可以在要单元测试业务类时注入虚假的数据访问对象。 DI设计避免了导致越野车,意大利面代码的许多陷阱。

使用DI时,通常建议您要求依赖项对象作为接口而不是具体类型(例如IPersonDataAccess而不是PersonDataAccess)。这样做可能会有点麻烦,但你很快就会习惯。由于您经常在这一点上为每个类创建一个接口,因此将接口放在与类相同的代码文件中很方便。因此,例如,PersonBusiness.vb将包含PersonDataAccess类和IPersonDataAccess接口。

为什么有使用接口,而不是类,为您的依赖两方面的原因是很重要的:

  1. 它确保了设计灵活。您希望能够覆盖依赖类型的每个公共成员,以便您可以创建任何类型的具体实现。还有其他方法可以做到这一点。例如,您可以跳过创建IPersonDataAcess界面,方法是使用Overrideable修饰符简单标记PersonDataAccess类中的每个公共属性和方法,但没有任何东西强迫您这样做。即使你一直记得这样做,这并不意味着别人在你的代码上工作会知道他们应该这样做。

    DI通常与单元测试捆绑在一起,因为它是确保代码可测试的最佳工具。在进行单元测试时,能够以依赖类型覆盖永远的成员是非常重要的,所以你可以创建一个“假”对象,它可以按照你需要的方式工作,以便正确执行单元测试。这些“假”物体被称为模拟

  2. 你对技术上的依赖性更加诚实。实际上,你并不是说你的依赖实际上是类的一个实例。实际上,您的依赖关系是碰巧拥有相同公共接口的任何对象。通过请求课堂,你意味着你需要一个特定的实现,这是一个谎言。如果你设计得当,你只关心接口是相同的,所以通过只询问接口本身,你正在明确地指定你的意思是什么:)

+0

谢谢。 +1用于参考DI。你会为所有类创建接口吗? PersonDto在哪里定义?我认为它和我的Person类相同? – w0051977

+0

是的,我的例子中'PersonDto'被假定为和你问题中的'Person'类相同。对困惑感到抱歉。是的,我会推荐为所有非DTO类创建接口。如果你制作一个基本上只用于一个类的接口,我会建议把它和类放在同一个代码文件中。因此,例如,PersonBusiness.vb将包含“PersonBusiness”类和“IPersonBusiness”接口。 –

+0

我喜欢将类文件和接口放在同一个文件中,因为它会使项目变得粗糙。我不完全理解接口的好处。如果系统需要更改,那么肯定需要更改 - 如果您有接口,则无关紧要,但无论我在网上看起来如何,似乎都暗示了它的作用。在我接受你的答案之前,你能举个例子吗?谢谢。 – w0051977