Excel VBA类集合如何集成到接口与工厂方法的问题咨询
核心问题汇总
- 类型声明不匹配:标准模块中
oTest声明为FTestClass类型,但CTestClass.Create返回的是ITestClass类型,类型不兼容导致赋值失败,oTest为Nothing,调用任何成员都会报错 - 类职责混淆:将单个数据实体和集合容器的逻辑写在同一个类中,导致每个实体实例都冗余持有一个空集合,接口定义同时包含实体属性和集合方法,逻辑冲突
- 预声明ID配置错误:需要直接用类名调用的工厂类/带默认实例的类需要将
VB_PredeclaredId设为True,你当前配置刚好相反,导致CTestClass.Create无法正确调用你写的Create方法 - 缺少For Each遍历支持:自定义类要支持For Each遍历必须添加
NewEnum属性并指定成员ID为-4,你的类没有该配置,即使对象有效也无法遍历 - 函数未返回值:
Extract方法定义为返回ITestClass类型,但方法内没有Set Extract = Me这类返回语句,逻辑不完整 - 接口职责混乱:
ITestClass同时定义了单个实体的Name、Cost属性和集合的Item、Count方法,单个实体实例调用集合方法时必然报错
修复方案
按照你的业务需求(多输入表统一输出),建议拆分职责为四类模块,避免逻辑耦合:
1. 输出实体接口 IOutputEntry.cls(预声明ID=False)
仅定义统一输出的12个字段属性,和集合逻辑完全隔离
Option Explicit Public Property Get Name() As String End Property Public Property Get Cost() As Long End Property ' 其他10个输出字段同理定义
2. 输入表实体类 CTestEntry.cls(预声明ID=False)
对应单张输入表的单条数据,实现统一输出接口
Option Explicit Implements IOutputEntry Private Type TEntry Name As String Cost As Long End Type Private this As TEntry Friend Property Let Name(v As String) this.Name = v End Property Private Property Get IOutputEntry_Name() As String IOutputEntry_Name = this.Name End Property Friend Property Let Cost(v As Long) this.Cost = v End Property Private Property Get IOutputEntry_Cost() As Long IOutputEntry_Cost = this.Cost End Property
3. 统一集合类 COutputCollection.cls(预声明ID=False)
仅负责存储统一输出接口实例,支持遍历
Option Explicit Private coll As Collection Private Sub Class_Initialize() Set coll = New Collection End Sub Public Sub Add(entry As IOutputEntry) coll.Add entry, Key:=entry.Name End Sub Public Property Get Item(index As Variant) As IOutputEntry Set Item = coll.Item(index) End Property Public Property Get Count() As Long Count = coll.Count End Property ' 支持For Each遍历,需要用文本编辑器打开cls文件添加以下Attribute ' Attribute NewEnum.VB_UserMemId = -4 Public Property Get NewEnum() As IUnknown Set NewEnum = coll.[_NewEnum] End Property
4. 单表工厂类 FTestEntryFactory.cls(预声明ID=True)
负责读取指定输入表、生成实体、打包为统一集合返回
Option Explicit ' 表格配置,可根据不同输入表调整 Private Const WS_NAME As String = "Sheet1" Private Const NR_TBL As String = "Table1" Private Enum icrColRef icrName = 2 icrCost = 4 End Enum Public Function Create() As COutputCollection Dim tbl As ListObject, i As Long, entry As CTestEntry Set Create = New COutputCollection Set tbl = ThisWorkbook.Worksheets(WS_NAME).ListObjects(NR_TBL) For i = 1 To tbl.DataBodyRange.Rows.Count Set entry = New CTestEntry With entry .Name = tbl.DataBodyRange(i, icrName).Value .Cost = tbl.DataBodyRange(i, icrCost).Value End With Create.Add entry Next i End Function
5. 测试代码(标准模块)
Sub TestFactory() Dim entries As COutputCollection, entry As IOutputEntry Set entries = FTestEntryFactory.Create ' 直接用预声明的工厂类实例调用 For Each entry In entries Debug.Print entry.Name, entry.Cost Next End Sub
后续新增其他输入表时,仅需要新增对应的实体类、工厂类即可,输出都基于IOutputEntry和COutputCollection,完全满足统一输出的需求。
内容的提问来源于stack exchange,提问作者SquirrelBait
相关产品推荐
相关产品推荐

