重构为 n 层

发布于 2024-07-07 08:24:06 字数 780 浏览 10 评论 0原文

我是一名自学的 vb6 程序员,使用 DAO。 下面是我可以编写的一段典型代码的示例:

Sub cmdMultiplier_Click()  'Button on form, user interface ' 
  dim Rec1 as recordset
  dim strSQL as string

  strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID  'inline SQL '
  set rec1 = GlobalDataBase.openrecordset(strSQL)    ' Data access '

  if rec1.bof <> true or rec1.eof <> true then
    if rec1.fields("Category").value = 1 then
      PriceMultiplier = 0.9         ' Business Logic ' 
    else
      priceMultiplier = 1
    end if
 end if
End Sub

请假装上面是 CRUD 应用程序的完整源代码。 我知道这个设计很糟糕,所有东西都混在一起了。 理想情况下,它应该具有三个不同的层:用户界面、业务逻辑 和数据访问。 我有点明白为什么这是可取的,但我不知道它是如何完成的,我怀疑 这就是为什么我不完全明白为什么这样的分离是好的。 我认为如果有人可以荒谬地重构上述内容,我会走得更远 将一个简单的例子分为 3 层。

I am a self taught vb6 programmer who uses DAO. Below is an example of a typical piece of code that I could churn out:

Sub cmdMultiplier_Click()  'Button on form, user interface ' 
  dim Rec1 as recordset
  dim strSQL as string

  strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID  'inline SQL '
  set rec1 = GlobalDataBase.openrecordset(strSQL)    ' Data access '

  if rec1.bof <> true or rec1.eof <> true then
    if rec1.fields("Category").value = 1 then
      PriceMultiplier = 0.9         ' Business Logic ' 
    else
      priceMultiplier = 1
    end if
 end if
End Sub

Please pretend that the above is the entire source code of a CRUD application.
I know this design is bad, everything is mixed up together. Ideally it should have three distinct layers, user interface, business logic
and data access. I sort-of get why this is desirable but I don't know how it's done and I suspect
that's why I don't fully get why such a separation is good.
I think I'd be a lot further down the road if someone could refactor the above ridiculously
trivial example into 3 tiers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

酒解孤独 2024-07-14 08:24:07

该按钮的用途是什么?

我的第一步是:

  • 提取访问数据库的部分。 (警告:前面有空代码)
function getCustomer(CurrentCustomerID as Long)

strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID
set rec1 = GlobalDataBase.openrecordset(strSQL)
result = 1

if rec1.recordcount >0 then
    getCustomer = rec1
else
    getCustomer = false
endif
end function
  • 编写业务逻辑函数:
function getCustomerDiscount(customerID as Long)

customer = getCustomer(customerID)

res = 1
if customer then
    if customer("category")=1) then
        res = .9
    endif
endif

getcustomerdiscount = res

end function
  • 然后,更改按钮:
Sub cmdMultiplier_Click() 
    pricemultiplier = getcustomerdiscount(currentcustomerid)
end sub

What is the purpose of the button?

My first steps would be:

  • extract the part accessing the database. (warning: air code ahead)
function getCustomer(CurrentCustomerID as Long)

strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID
set rec1 = GlobalDataBase.openrecordset(strSQL)
result = 1

if rec1.recordcount >0 then
    getCustomer = rec1
else
    getCustomer = false
endif
end function
  • compose the business logic function:
function getCustomerDiscount(customerID as Long)

customer = getCustomer(customerID)

res = 1
if customer then
    if customer("category")=1) then
        res = .9
    endif
endif

getcustomerdiscount = res

end function
  • then, change the button:
Sub cmdMultiplier_Click() 
    pricemultiplier = getcustomerdiscount(currentcustomerid)
end sub
七分※倦醒 2024-07-14 08:24:06

是的,这是一个简单的例子,但具有所有基本元素 - 它们只是属于 3 个不同的类别(见下文)。 主要原因是“关注点分离”原则,即GUI只关心GUI的东西,Biz逻辑层只关心业务规则,而数据访问层只关心数据表示。 这允许每个层独立维护并跨应用程序重用:

'in Form class - button handler
Sub cmdMultiplier_Click()
    PriceMultiplier = ComputePriceMultiplier(CurrentCustomerId)
End Sub

'in Biz Logic class
Function ComputePriceMultiplier(custId as Integer) as Double
    Dim cust as Customer = GetCustomer(custId)
    if cust.Category = 1 then   'please ignore magic number, real code uses enums
        return 0.9
    end if
    return 1
End Function

'in Data Access Layer class
Function GetCustomer(custId as Integer) as Customer
    Dim cust as Customer = New Customer    'all fields/properties to default values
    Dim strSQL as String = "select * from tblCustomers where ID = " & custId
    set rec1 = GlobalDataBase.openrecordset(strSQL)    ' Data access '
    if rec1.bof <> true or rec1.eof <> true then
        cust.SetPropertiesFromRecord(rec1)
    end if
    return cust
End Function

[“真实”应用程序将缓存当前客户,具有用于客户查询的常量或存储过程等; 为简洁起见,忽略]

将此与您原来的一切按钮处理程序示例进行对比(这在 VB 代码中非常常见,因为这样做很容易) - 如果您需要在另一个应用程序中使用价格乘数规则,您必须将代码复制、粘贴并编辑到该应用程序的按钮处理程序中。 现在将有两个地方维护相同的业务规则,并且有两个地方执行相同的客户查询。

a trivial example, yes, but with all the basic elements - they just belong in 3 different classes (see below). The main reason for this is the "separation of concerns" principle, i.e. the GUI is only concerned with GUI things, the Biz Logic layer is only concerned with the business rules, and the data-access layer is only concerned with data representations. This allows each layer to be maintained independently and reused across applications:

'in Form class - button handler
Sub cmdMultiplier_Click()
    PriceMultiplier = ComputePriceMultiplier(CurrentCustomerId)
End Sub

'in Biz Logic class
Function ComputePriceMultiplier(custId as Integer) as Double
    Dim cust as Customer = GetCustomer(custId)
    if cust.Category = 1 then   'please ignore magic number, real code uses enums
        return 0.9
    end if
    return 1
End Function

'in Data Access Layer class
Function GetCustomer(custId as Integer) as Customer
    Dim cust as Customer = New Customer    'all fields/properties to default values
    Dim strSQL as String = "select * from tblCustomers where ID = " & custId
    set rec1 = GlobalDataBase.openrecordset(strSQL)    ' Data access '
    if rec1.bof <> true or rec1.eof <> true then
        cust.SetPropertiesFromRecord(rec1)
    end if
    return cust
End Function

[a 'real' application would cache the current customer, have constants or stored procedures for the customer query, etc.; ignored for brevity]

Contrast this with your original everything-in-the-button-handler example (which is appallingly common in VB code because it is so easy to do it that way) - if you needed the price-multiplier rule in another application, you'd have to copy, paste, and edit the code into that application's button-handler. Now there would be two places to maintain the same business rule, and two places where the same customer query was executed.

烟燃烟灭 2024-07-14 08:24:06

通常,您的 UI 代码会响应用户引发的事件,在本例中为“按钮单击”。

之后,这实际上取决于您的程序的设计方式,最基本的设计是引用 Customer 实例,并且它将包含一个 multiplier 属性。
您的客户对象是根据 DAL 中的数据填充的。

UI 的验证将进入 UI 层,业务验证规则可以进入您的业务对象,然后您的 DAL 就是您的持久层。

这是一个非常基本的伪代码示例:

btnClick
    Dim Cust as New Customer(ID)
    multplr = Cust.DiscountMultiplier
End Click

Class Customer
    Sub New(ID)
        Data = DAL.GetCustomerData(ID)
        Me.Name = Data("Name")
        Me.Address = Data("Address")
        Me.DiscountMultiplier = Data("DiscountMultiplier")
    End Sub
    Property ID
    Property Name
    Property Address
    Property DiscountMultiplier
        Return _discountMultiplier
    End
End Class


Class DAL
    Function GetCustomerData(ID)
        SQL = "Paramaterized SQL"
        Return Data
    End Function
End Class

Typically you will have your UI code responding to the events raised by the user, in this case the Button Click.

After that it really depends on how your program is designed, the most basic design would be to reference a Customer instance and it would contain a multiplier property.
Your customer object is populated from data in your DAL.

Validation for UI would go in UI layer, business validation rules could go into your business object, and then your DAL is your persistence layer.

Here is a very basic pseudo-code example:

btnClick
    Dim Cust as New Customer(ID)
    multplr = Cust.DiscountMultiplier
End Click

Class Customer
    Sub New(ID)
        Data = DAL.GetCustomerData(ID)
        Me.Name = Data("Name")
        Me.Address = Data("Address")
        Me.DiscountMultiplier = Data("DiscountMultiplier")
    End Sub
    Property ID
    Property Name
    Property Address
    Property DiscountMultiplier
        Return _discountMultiplier
    End
End Class


Class DAL
    Function GetCustomerData(ID)
        SQL = "Paramaterized SQL"
        Return Data
    End Function
End Class
你与昨日 2024-07-14 08:24:06

知道如何重构是一件好事。 从现在起您将知道如何分离图层。
不过,我认为您最好花时间来升级您同时使用的工具。 你有考虑过用VB.Net来做吗?

保留现有代码库的一种方法是在 VB.Net 中对数据层和 BR 进行编码。 然后通过COM接口公开BR(这是项目中的复选框选项)。 然后,您可以从当前界面使用新的 BR。

完成所有 BR 和 DAL 后,您将迈向全新平台。

Knowing how to refactor is a good thing. From now you will know how to separate layers.
However, I think your time will be better spend to upgrade the tools you are using at the same time. Do you have consider to do it with VB.Net ?

A way to do it will preserving your existing code base is to code the Data layer and BR in VB.Net. Then to expose the BR through COM Interface (this is a check box option in the project). You can then use the new BR from your current interface.

Once all BR and DAL done, you will be a step away to a complete new platform.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文