Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Please see the code below:

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

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.

like image 995
w0051977 Avatar asked Jan 01 '13 17:01

w0051977


1 Answers

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

like image 133
Steven Doggart Avatar answered Sep 20 '22 21:09

Steven Doggart