vb.net 将 BLL(业务逻辑层)分解为 BLL 和 DAL(数据访问层)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14112392/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Breaking BLL (Business Logic Layer) to BLL and DAL (Data Access Layer)
提问by w0051977
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.
PersonBLL 调用 PersonDAL 并返回一个 Person 对象。这是正确的方法吗?即我已经确定了一个持久类并创建了一个相应的 DAL 类,其中包含一个用于访问数据和返回 Person 对象的函数。
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.
有评论指出这个问题是“主观的”。我同意这一点。我意识到设计取决于项目的要求。是否有任何记录用于设计类似于 SOLID(单一职责等)等的 DAL 的原则。
采纳答案by Steven Doggart
Yes, your question demonstrates a very clean way to separate the logic into layers. The PersonBLLclass would be part of the business layer, the PersonDALclass would be part of the data access layer, and the Personclass 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.
是的,您的问题展示了一种非常干净的将逻辑分成多个层的方法。的PersonBLL类将是业务层的一部分,PersonDAL类将是数据访问层的一部分,并且所述Person类将是数据传输对象(DTO)层的一部分。这是一种非常常见的分离图层的方法,在许多情况下都能很好地工作。
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.getPersonByIDfrom 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.
- 你应该把每一层放在他们自己的命名空间中,如果不是还有他们自己的类库项目。
- 您不应显示来自业务层的消息框。我假设你这样做只是为了演示,但为了以防万一,我想我应该提到它。显示消息框应该是 UI 层的一部分。例如,如果您
PersonBLL.getPersonByID从 Windows 服务或 Web 服务调用,则显示消息框是完全不合适的。 - 通常,所有方法都是PascalCase,而不是camelCase。有些人更喜欢将私有方法设为驼峰式,但当然公共方法不应该是驼峰式。
- 考虑使用依赖注入技术 (DI) 将数据访问对象注入业务对象。
Dependency Injection
依赖注入
Here's an example of how to do this with DI techniques:
以下是如何使用 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
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 设计避免了许多导致错误、意大利面条式代码的陷阱。
With DI, it is typically recommended that you ask for dependency objects as an interface rather than as a concrete type (e.g. IPersonDataAccessrather 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 PersonDataAccessclass and the IPersonDataAccessinterface.
对于 DI,通常建议您将依赖对象作为接口而不是具体类型(例如,IPersonDataAccess而不是PersonDataAccess)。这样做可能有点麻烦,但您很快就会习惯它。由于您经常在那时为每个类创建一个接口,因此将接口与类放在同一代码文件中会很方便。因此,例如,PersonBusiness.vb 将包含PersonDataAccess类和IPersonDataAccess接口。
There are two reasons why using interfaces, rather than classes, for your dependencies is important:
对依赖项使用接口而不是类很重要的原因有两个:
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
IPersonDataAcessinterface by simply marking every public property and method in thePersonDataAccessclass with theOverrideablemodifier, 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.
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
PersonDataAccessclass. 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 :)
它确保设计是灵活的。您希望能够覆盖依赖项类型的每个公共成员,以便您可以创建任何类型的具体实现。还有其他方法可以做到这一点。例如,您可以
IPersonDataAcess通过简单地PersonDataAccess用Overrideable修饰符标记类中的每个公共属性和方法来跳过创建接口,但没有什么强迫您这样做。即使您一直记得这样做,但这并不意味着其他处理您代码的人会知道他们应该这样做。DI 通常与单元测试相关联,因为它是确保代码可测试的最佳工具。进行单元测试时,能够覆盖依赖类型中的任何成员尤为重要,这样您就可以制作一个“假”对象,该对象按照您需要的方式工作,以便正确执行单元测试。这些“假”对象称为mocks。
您在技术上对您的依赖项更加诚实。实际上,您并不是说您的依赖项实际上是
PersonDataAccess该类的一个实例。实际上,您的依赖项是任何碰巧具有相同公共接口的对象。通过要求类,你暗示你需要一个特定的实现,这是一个谎言。如果你设计得当,你只关心界面是否相同,所以通过只要求界面本身,你就准确地指定了你要指定的内容:)

