类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
相关产品推荐
相关产品推荐

