将BLL(业务逻辑层)打破BLL和DAL(数据访问层) [英] Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)

查看:117
本文介绍了将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对象的功能。

PersonBLL calls PersonDAL and returns a Person object. Is this the correct approach? i.e. I have identified a persistent class and created a corresponding DAL class with a function for accessing the data and returning the Person object.

有一个注释说明了这个问题是主观的。我同意这一点。我意识到设计依赖于项目的要求。有没有关于设计类似于SOLID(单一责任等)等的DAL的任何原则。

There is a comment that states that this question is "subjective". I agree with this. I realise that the design depends on the requirements of the project. Are there any principles documented for designing a DAL similar to SOLID (single responsibility etc) etc.

推荐答案

是的,您的问题显示非常干净的方式将逻辑分为多层。 PersonBLL 类将成为业务层的一部分, PersonDAL 类将成为数据访问层的一部分, Person 类将成为数据传输对象(DTO)层的一部分。这是一种非常常见的方法,可以在多种情况下分离出有用的图层。

Yes, your question demonstrates a very clean way to separate the logic into layers. The PersonBLL class would be part of the business layer, the PersonDAL class would be part of the data access layer, and the Person class would be part of the data transfer objects (DTO) layer. This is a very common way to separate your layers which works well in many situations.

我唯一的建议是:


  • 您应该将每个层都放在自己的命名空间中,如果不是也是他们自己的类库项目。

  • 你不应该在业务中显示一个消息框层。我假设你只是作为示威的手段,但为了防万一,我以为我应该提到它。显示消息框应该是UI层的一部分。例如,如果您从Windows服务或Web服务调用 PersonBLL.getPersonByID ,则显示一个消息框将是完全不合适的。

  • <通常,所有的方法都是PascalCase,而不是camelCase。有些人更喜欢使用私有的方法,但肯定公共方法不应该是骆驼案例。
  • 考虑使用依赖注入技术(DI)将数据访问对象注入到业务对象。

  • You should put each layer in their own namespaces, if not also their own class library projects.
  • You should not show a message box from the business layer. I assume you only did this as a means of demonstration, but just in case, I thought I should mention it. Showing a message box should be part of the UI layer. For instance, if you were calling PersonBLL.getPersonByID from a windows service or a web service, showing a message box would be entirely inappropriate.
  • Typically, all methods are PascalCase, not camelCase. Some people prefer to make private methods camel case, but certainly public methods shouldn't be camel case.
  • Consider using dependency-injection techniques (DI) to inject the data access object into the business object.

依赖注入

一个使用DI技术的例子:

Here's an example of how to do this with DI techniques:

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设计避免了许多导致错误的意大利面条代码的陷阱。

Doing it this way has many advantages. You can have multiple interchangeable data access layer implementations, so it's more flexible. Also, you can inject a fake data access object when you want to unit test the business class. DI design avoids many of the traps that lead to buggy, spaghetti code.

使用DI,通常建议您将依赖对象作为界面,而不是作为具体类型(例如 IPersonDataAccess 而不是 PersonDataAccess )。这样做可能有点麻烦,但您可以快速使用它。由于您经常在这一点上为每个类创建一个界面,所以只需将界面放在与类相同的代码文件中即可。所以,例如,PersonBusiness.vb将同时包含 PersonDataAccess 类和 IPersonDataAccess 接口。

With DI, it is typically recommended that you ask for dependency objects as an interface rather than as a concrete type (e.g. IPersonDataAccess rather than PersonDataAccess). Doing so can be a little bit of a hassle, but you get use to it quickly. Since you are often, at that point, creating one interface for every class, it's convenient to just put the interface in the same code file as the class. So, for instance, PersonBusiness.vb would contain both the PersonDataAccess class and the IPersonDataAccess interface.

有两个原因,为什么使用界面而不是类,您的依赖关系很重要:

There are two reasons why using interfaces, rather than classes, for your dependencies is important:


  1. 它确保设计灵活。您希望能够覆盖依赖关系类型的每个公共成员,以便您可以创建任何类型的具体实现。还有其他方法可以做到这一点。例如,您可以通过简单地标记 PersonDataAccess 类中的每个公共属性和方法来跳过创建 IPersonDataAcess 接口可覆盖修饰符,但没有什么强制你这样做。即使你总是记得这样做,这并不意味着你的代码上的其他人都知道他们应该这样做。

  1. It ensures that the design is flexible. You want to be able to override every public member of the dependency type so that you can create any kind of concrete implementation. There are other ways to do this. For instance, you could skip creating the IPersonDataAcess interface by simply marking every public property and method in the PersonDataAccess class with the Overrideable modifier, but there's nothing forcing you to do that. Even if you always remembered to do so, that doesn't mean someone else working on your code would know they should do that.

DI经常与单元捆绑在一起测试是因为它是确保代码可测试的最佳工具。当进行单元测试时,尤其重要的是您可以覆盖依赖类型中的所有成员,因此您可以制作一个假对象,只需按照您需要的方式工作即可正常执行单元测试。这些伪造对象称为 mocks

DI is often tied-in with unit testing because it is the best tool available for ensuring that code is testable. When unit testing, it is particularly important that you are able to override ever member in a dependency type so you can make a "fake" object that works just the way you need it to work in order to properly perform the unit test. These "fake" objects are called mocks.

您在技术上对您的依赖关系更诚实。实际上,你并不是说你的依赖实际上是一个 PersonDataAccess 类的实例。实际上,您的依赖关系是具有相同公共接口的任何对象。通过要求上课,你意味着你需要一个特定的实现,这是谎言。如果你正确地设计了它,你只需要关心接口是一样的,所以通过询问接口本身,你正在明确指定你的意思来指定:)

You are being more technically honest about what your dependency is. In reality, you aren't really saying that your dependency is actually an instance of the PersonDataAccess class. In actuality, your dependency is any object that happens to have that same public interface. By asking for the class, you are implying that you need a particular implementation, which is a lie. If you have designed it properly, you only care about the interface being the same, so by asking only for the interface itself, you are specifying precisely what you mean to specify :)

这篇关于将BLL(业务逻辑层)打破BLL和DAL(数据访问层)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆