Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)

前端 未结 1 1406
[愿得一人]
[愿得一人] 2020-12-31 20:43

Please see the code below:

Imports Microsoft.VisualBasic

Public Class PersonBLL
    Private Name As String
    Private Age As Integer

    Dim objPersonDAL          


        
相关标签:
1条回答
  • 2020-12-31 21:13

    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.

    My only recommendations would be:

    • 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.

    Dependency Injection

    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
    

    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.

    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. 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 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.

    2. 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 :)

    0 讨论(0)
提交回复
热议问题