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的原则.
我唯一的建议是:
>您应该将每个图层放在它们自己的名称空间中,如果不是它们自己的类库项目.
>您不应该从业务层显示消息框.我假设你只是作为一种示范手段,但为了以防万一,我想我应该提一下.显示消息框应该是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接口.
为依赖项使用接口而不是类,有两个原因很重要:
>它确保设计灵活.您希望能够覆盖依赖关系类型的每个公共成员,以便您可以创建任何类型的具体实现.还有其他方法可以做到这一点.例如,您可以通过使用Overrideable修饰符简单地标记PersonDataAccess类中的每个公共属性和方法来跳过创建IPersonDataAcess接口,但是没有任何强迫您这样做.即使你总是记得这样做,但这并不意味着其他人正在研究你的代码会知道他们应该这样做.
DI经常与单元测试捆绑在一起,因为它是确保代码可测试的最佳工具.在单元测试时,特别重要的是你能够覆盖依赖类型中的任何成员,这样你就可以制作一个“假的”对象,它可以按照你需要它的方式工作,以便正确地执行单元测试.这些“虚假”物体被称为嘲笑.>你在技术上更诚实地说明你的依赖是什么.实际上,您并不是说您的依赖项实际上是PersonDataAccess类的实例.实际上,您的依赖项是碰巧具有相同公共接口的任何对象.通过要求上课,你暗示你需要一个特定的实现,这是一个谎言.如果你已经正确设计了它,你只关心接口是否相同,所以通过只询问接口本身,你正在准确指定你的意思指定:)