You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

类Getter实现关联数据查询的合理性及VBA代码优化建议

问题咨询

我正在开发多个相互关联的类,需要让ObjClient类能够获取所有与自身About.ClientId匹配的ObjInvoice实例。目前我通过一个名为Invoices的Getter属性实现该功能,但不确定此方式是否违反编程原则,特向各位编程专家请教可行方案;同时也欢迎针对以下VBA代码提供其他优化建议。

现有VBA代码

Private Rng_ As Range
Private About_ As New ClAbout
Private Status_ As New ClStatus
Private ServiceInfo_ As New ClServiceInfo
Private ContactPlan_ As New ClContactPlan

Public Sub Init(Optional ByVal WsRow As Long, Optional ByVal ListRow As Long, Optional InitNew As Boolean = False)
'根据传入的行查找客户区域
If WsRow <> 0 Then
    Set Rng_ = DbWs.Rows(WsRow)
ElseIf ListRow <> 0 Then
    Set Rng_ = DbTbl.ListRows(ListRow).Range.EntireRow
ElseIf InitNew = False Then
    MsgBox ("未提供客户行。")
End If
InitSubclasses
End Sub

Public Sub InitSubclasses(Optional InitNew As Boolean = False)
'初始化子类
About_.Init Me, InitNew
Status_.Init Me, InitNew
ServiceInfo_.Init Me, InitNew
ContactPlan_.Init Me, InitNew

If About_.Company = "PP" And _
    Status_.CurrentStatus <> "DNC" Then
    About_.IsActive = True
Else
    About_.IsActive = False
End If
End Sub

Sub AddNew()
Dim Cl As ObjClient
HighestId = 0
For Each Cl In ClientCol
    If HighestId < Cl.About.ClientId Then
        HighestId = Cl.About.ClientId
    End If
Next
About_.ClientId = HighestId + 1

'根据传入的行查找客户区域
Set Rng_ = DbTbl.ListRows.Add.Range.EntireRow

UploadDBInfo
ClientCol.Add Me

End Sub

Sub Remove()

Me.Rng.Delete xlShiftUp

For i = 1 To ClientCol.Count
    If ClientCol(i).About.ClientId = Me.About.ClientId Then
        ClientCol.Remove i
        Exit For
    End If
Next
End Sub

Public Sub UploadDBInfo()

'检查变更并更新已修改的分类
If About_.HasChanged = True Then
    About_.UpdateAbout
End If
If ServiceInfo_.HasChanged = True Then
    ServiceInfo_.UpdateServiceInfo
End If
If ContactPlan_.CallBack.HasChanged = True Then
    ContactPlan_.CallBack.UpdateCallBack
End If
If ContactPlan_.SmartPlan.HasChanged = True Then
    ContactPlan_.SmartPlan.UpdateSPlan
End If
If Status_.HasChanged = True Then
    Status_.UpdateStatus
End If
End Sub

'创建Getter和Setter
Property Get Invoices() As Collection
Dim Invoice As ObjInvoice
Dim Col As Collection
'InvCol是存储ObjInvoice实例的公共集合
For Each Invoice In InvCol
    If Invoice.About.ClientId = Me.About.ClientId Then Col.Add Invoice
Next
Set Invoices = Col
End Property

Property Get Rng() As Range
Set Rng = Rng_
End Property

'子对象
Property Get About() As ClAbout
Set About = About_
End Property
'
Property Get Status() As ClStatus
Set Status = Status_
End Property

Property Get ServiceInfo() As ClServiceInfo
Set ServiceInfo = ServiceInfo_
End Property

Property Get ContactPlan() As ClContactPlan
Set ContactPlan = ContactPlan_
End Property

问题解答与优化建议

关于Invoices属性的实现合理性

  • 这种实现本身不违反核心编程原则,但存在几个可优化的点:
    • 性能损耗:每次调用Invoices都会遍历整个InvCol集合,若集合规模大、调用频繁,会拖慢程序。建议缓存匹配的发票集合,在发票数据更新时同步刷新缓存。
    • 耦合问题:ObjClient直接依赖全局InvCol集合,不符合依赖倒置原则。可通过注入专门的InvoiceManager类解耦,让ObjClient通过服务获取对应发票,而非直接访问全局集合。
    • 空引用风险:当前代码中Col未初始化,若无匹配发票会抛出错误,需在循环前添加Set Col = New Collection避免问题。

其他代码优化点

  • 子对象初始化:As New会导致延迟初始化,易在意外时机创建实例。建议在Init或InitSubclasses中显式初始化子对象(如Set About_ = New ClAbout),而非声明时用As New。
  • 变量类型声明:AddNew中的HighestId、Remove中的i未声明类型,易引发类型错误,需添加Dim HighestId As Long、Dim i As Integer(或Long)。
  • 错误处理:Init、AddNew、Remove等核心方法缺少异常捕获,一旦出错会导致程序崩溃,建议添加On Error GoTo或On Error Resume Next块处理异常。
  • ID生成效率:遍历ClientCol找最大ID的方式效率低下,尤其客户数量多时。可维护全局NextClientId变量,或直接从数据库表获取最大ID,避免循环遍历。
  • 访问修饰符:AddNew和Remove默认是Private,若需外部调用应改为Public。
  • 硬编码字符串:"PP"、"DNC"等硬编码字符串建议定义为常量,便于统一维护修改。

内容的提问来源于stack exchange,提问作者Austin Weiss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:22:35