尝试#2 - VBA中的继承解决方法 [英] Try #2 - Inheritance work-around in VBA

查看:156
本文介绍了尝试#2 - VBA中的继承解决方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我尝试并做了一个糟糕的工作,解释了我有处理的想法

a特定的实施继承案例,这很简单明了

in一个完全OOP语言,但在VBA中没有显而易见的,它缺少

继承。我现在正在再次尝试解释。


我经常发现有限形式的继承会消除

重复我的代码似乎无法消除的情况除此以外。现在,我正在非常严格地对待重复,因为在稍后修改

代码时会出现seroius错误来源。在您尝试严格对待它之后,然后尝试使用那些不是那样写的代码工作,你会很快看到我的意思。


所以,我所谈论的继承的具体情况是一个基类,

包含操作所需的大部分代码和接口,但是

该操作需要有几个小的变化,主要是包含操作内部属性和功能的
,而不是暴露给外部代码



假设我有一个应用程序,其中代码经常需要在给定名称的查找表中检索项目的

ID,并自动插入

项目如果它不存在则首先。现在,假设我需要在不同的时间对许多不同的表执行相同的操作。我们还假设,在这个

应用程序中,每个表都具有对于

代码的特定部分已知的硬含义。我们并没有解决在
循环等中抽象地处理类型集合的问题(这将是另一个层与另一个解决方案)。


如果我们有继承在语言能力方面,设计模式将是明显的b $ b。基类(Abstract类)包含逻辑,并且每个查找表的

继承类(Concrete类)提供值为表名的基类
,名称字段和ID字段。 Abstract类



具体元素提供虚拟(未在基类中实现)私有成员,每个Concrete类提供
$ b的实现$ b那些,所以Abstract类中的代码可以访问它们。


继承通常用VBA等语言模拟的方式是

Concrete类封装(包含对Abstract类的引用),并且

通过包装器方法提供对Abstract类'成员的外部访问权限

。对于我所描述的情况,这是一个完全混乱,这就是为什么

这种情况​​是这样一个问题并且需要这个解决方案;它删除了多少

重复。每个Concrete类必须实现并公开

其所有具体成员(外部代码不需要)以及一个包装器

for Abstract的每个公共成员class(具体类

没有实现)。

我的解决方案是反转封装,以便抽象类。 class

封装了混凝土类。外部代码与

Abstract相互作用。直接类,该类调用混凝土上课到

获取手头案例的具体细节。


工作代码示例如下。请注意,具体类可以提供

进程(例如特殊初始化)以及静态属性。

- basTests


选项比较数据库

选项明确


公共函数GetNewLookupValueList(_

objValueListConcrete As IValueListConcrete _

)as clsLookupValueList

Dim objLookupValueList As new clsLookupValueList

objLookupValueList.Setup objValueListConcrete

设置GetNewLookupValueList = objLookupValueList

结束函数


Sub RunTests()

使用GetNewLookupValueList(新clsLookupValListColor)

Debug.Print .IdFromName(" Blue")

结束


使用GetNewLookupValueList(新clsLookupValListStyle)

Debug.Print .IdFromName(" Gaudy")

结束

结束次级

- clsLookupValueList -


选项比较数据库

选项明确

私人mobjConcrete As IValueListConcrete

私人mdbs作为DAO.Database

私人mrst作为DAO.Recordset


公共子设置(_

objValueListConcrete As IValueListConcrete _



设置mobjConcrete = objValueListConcrete

结束Sub


私有财产获取SelectSql()作为字符串

使用mobjConcrete

SelectSql = _

SELECT &安培; _

.FieldNameId& , &安培; _

.FieldNameItem& " " &安培; _

" FROM" &安培; _

。表名

结束

结束物业


私人功能GetRecordset()作为DAO .Recordset

如果mrst什么都没有那么

设置mdbs = CurrentDb()

设置mrst = mdbs.OpenRecordset(SelectSql)

结束如果

设置GetRecordset = mrst

结束功能


私有财产获取IdField()作为DAO.Field

''可以公开,但现在不需要,所以不要公开。

设置IdField = GetRecordset.Fields(mobjConcrete.FieldNameId)

结束财产


私有财产获取ItemField()作为DAO.Field

''可以公开,但现在不需要,所以不公开。

设置ItemField = GetRecordset.Fields(mobjConcrete.FieldNameItem)

结束属性


公共函数IdFromName(strName As String)As Long

Dim varResult As Variant

varResult = Null

使用GetRecordset()

如果.RecordCount& GT; 0然后

.FindFirst _

mobjConcrete.FieldNameItem& " =" &安培; _

StringToSqlStringExpr(strName)

如果不是.NoMatch那么

varResult = IdField.Value

结束如果

结束如果

如果IsNull(varResult)那么

.AddNew

ItemField.Value = strName

。更新

.Bookmark = .LastModified

varResult = IdField.Value

结束如果

结束使用

IdFromName = varResult

结束函数

私有函数StringToSqlStringExpr(strString as String)As String

StringToSqlStringExpr ="''" &安培;替换(strString,"''","''''")& "''"

结束函数


公共函数NameFromID(LngID As Long)作为Variant

Dim varResult As Variant

varResult = Null

使用GetRecordset()

如果.RecordCount> 0然后

.FindFirst mobjConcrete.FieldNameId& " =" &安培; lngID

如果不是.NoMatch然后

varResult = IdField.Value

结束如果

结束如果

结束

NameFromID = varResult

结束功能


私有子Class_Terminate()

如果没有(第一个什么都没有)那么

mrst.Close

设置mrst = Nothing

结束如果

设置mdbs = Nothing

结束子

- IValueListConcrete -


选项比较数据库

选项明确


公共属性获取TableName()为字符串

结束属性


公共属性获取FieldNameId ()作为字符串

结束属性


公共属性获取FieldNameItem()为字符串

结束属性

- clsLookupValListColor -


选项比较数据库

选项明确


实现IValueListConcrete


私有财产获取IValueListConcrete_TableName()_

A s String

IValueListConcrete_TableName =" tblColor"

结束物业


私有财产获取IValueListConcrete_FieldNameId()_

As String

IValueListConcrete_FieldNameId =" ColorID"

结束财产


私有财产获取IValueListConcrete_FieldNameItem()_

As String

IValueListConcrete_FieldNameItem =" Color"

End Property

- clsLookupValListStyle -


选项比较数据库

选项明确


实现IValueListConcrete


私有财产获取IValueListConcrete_TableName ()_

As String

IValueListConcrete_TableName =" tblStyle"

结束物业


私人Property Get IValueListConcrete_FieldNameId()_

As String

IValueListConcrete_FieldNameId =" StyleID"

End Property


私有财产获取IValueListConcrete_FieldNameItem()_

As String

IValueListConcrete_FieldNameItem =" Style"

结束财产

Recently, I tried and did a poor job explaining an idea I''ve had for handling
a particular case of implementation inheritance that would be easy and obvious
in a fully OOP language, but is not at all obvious in VBA which lacks
inheritance. I''m trying the explanation again now.

I often find cases where a limited form of inheritance would eliminate
duplication my code that seems impossible to eliminate otherwise. I''m getting
very rigorous, now, about duplication because a seroius source of bugs when
code is modified later on. After you try being rigorous about it, then try to
work on code that''s not written that way, you''ll quickly see what I mean.

So, the specific case of inheritance I''m talking about is a base class that
contains the majority of the code and interfaces needed for an operation, but
there needs to be several minor variations on that operation, mainly
comprising attributes and functionality internal to the operation, not exposed
to external code.

Say I have an application in which the code frequently needs to retrieve the
ID of an item in a lookup table given the name, and automatically insert the
item first if it doesn''t exist. Now, say I need to do this same operation for
many different tables at different times. Let''s also assume that, in this
application, each table has a hard meaning known to specific parts of the
code. We are not addressing working with collections of types abstractly in
loops, etc. (that would be another layer with another solution).

If we had inheritance capability in the language, the design pattern would be
obvious. The base class (the Abstract class) contains the logic, and an
inheriting class (the Concrete class) for each lookup table provides values to
the base class for table name, name field, and ID field. The Abstract class
provides virtual (not implemented in the base class) private members for the
Concrete elements, and each Concrete class provides the implementations of
those, so the code in the Abstract class can access them.

The way inheritance is normally simulated in languages like VBA is that the
Concrete class encapsulates (contains a reference to) the Abstract class, and
provides external access to the Abstract class'' members via a wrapper method
for each. For the situation I''ve described, that''s a total mess, which is why
this case is such a prolem and in need of this solution; it adds as much
duplication as it removes. Every Concrete class has to implement and expose
all of its concrete members (that external code doesn''t need) plus a wrapper
for every single public member of the Abstract class (that the Concrete class
doesn''t implement).

My solution is to invert the encapsulation, so that the "Abstract" class
encapsulates the "Concrete" class. The external code interacts with the
"Abstract" class directly, and that class invokes the "Concrete" class to
obtain the specifics for the case at hand.

Working code example follows. Note that the concrete class could provide
processes (such as special initialization) as well as static properties.
-- basTests

Option Compare Database
Option Explicit

Public Function GetNewLookupValueList( _
objValueListConcrete As IValueListConcrete _
) As clsLookupValueList
Dim objLookupValueList As New clsLookupValueList
objLookupValueList.Setup objValueListConcrete
Set GetNewLookupValueList = objLookupValueList
End Function

Sub RunTests()
With GetNewLookupValueList(New clsLookupValListColor)
Debug.Print .IdFromName("Blue")
End With

With GetNewLookupValueList(New clsLookupValListStyle)
Debug.Print .IdFromName("Gaudy")
End With
End Sub
-- clsLookupValueList --

Option Compare Database
Option Explicit
Private mobjConcrete As IValueListConcrete
Private mdbs As DAO.Database
Private mrst As DAO.Recordset

Public Sub Setup( _
objValueListConcrete As IValueListConcrete _
)
Set mobjConcrete = objValueListConcrete
End Sub

Private Property Get SelectSql() As String
With mobjConcrete
SelectSql = _
"SELECT " & _
.FieldNameId & ", " & _
.FieldNameItem & " " & _
"FROM " & _
.TableName
End With
End Property

Private Function GetRecordset() As DAO.Recordset
If mrst Is Nothing Then
Set mdbs = CurrentDb()
Set mrst = mdbs.OpenRecordset(SelectSql)
End If
Set GetRecordset = mrst
End Function

Private Property Get IdField() As DAO.Field
'' Could be made public, but not needed now, so not exposed.
Set IdField = GetRecordset.Fields(mobjConcrete.FieldNameId)
End Property

Private Property Get ItemField() As DAO.Field
'' Could be made public, but not needed now, so not exposed.
Set ItemField = GetRecordset.Fields(mobjConcrete.FieldNameItem)
End Property

Public Function IdFromName(strName As String) As Long
Dim varResult As Variant
varResult = Null
With GetRecordset()
If .RecordCount > 0 Then
.FindFirst _
mobjConcrete.FieldNameItem & "=" & _
StringToSqlStringExpr(strName)
If Not .NoMatch Then
varResult = IdField.Value
End If
End If
If IsNull(varResult) Then
.AddNew
ItemField.Value = strName
.Update
.Bookmark = .LastModified
varResult = IdField.Value
End If
End With
IdFromName = varResult
End Function

Private Function StringToSqlStringExpr(strString As String) As String
StringToSqlStringExpr = "''" & Replace(strString, "''", "''''") & "''"
End Function

Public Function NameFromID(lngID As Long) As Variant
Dim varResult As Variant
varResult = Null
With GetRecordset()
If .RecordCount > 0 Then
.FindFirst mobjConcrete.FieldNameId & "=" & lngID
If Not .NoMatch Then
varResult = IdField.Value
End If
End If
End With
NameFromID = varResult
End Function

Private Sub Class_Terminate()
If Not (mrst Is Nothing) Then
mrst.Close
Set mrst = Nothing
End If
Set mdbs = Nothing
End Sub
-- IValueListConcrete --

Option Compare Database
Option Explicit

Public Property Get TableName() As String
End Property

Public Property Get FieldNameId() As String
End Property

Public Property Get FieldNameItem() As String
End Property
-- clsLookupValListColor --

Option Compare Database
Option Explicit

Implements IValueListConcrete

Private Property Get IValueListConcrete_TableName() _
As String
IValueListConcrete_TableName = "tblColor"
End Property

Private Property Get IValueListConcrete_FieldNameId() _
As String
IValueListConcrete_FieldNameId = "ColorID"
End Property

Private Property Get IValueListConcrete_FieldNameItem() _
As String
IValueListConcrete_FieldNameItem = "Color"
End Property
-- clsLookupValListStyle --

Option Compare Database
Option Explicit

Implements IValueListConcrete

Private Property Get IValueListConcrete_TableName() _
As String
IValueListConcrete_TableName = "tblStyle"
End Property

Private Property Get IValueListConcrete_FieldNameId() _
As String
IValueListConcrete_FieldNameId = "StyleID"
End Property

Private Property Get IValueListConcrete_FieldNameItem() _
As String
IValueListConcrete_FieldNameItem = "Style"
End Property

推荐答案

2004年4月13日星期二07:20:06 GMT,Steve Jorgensen< no **** @ nospam.nospam>

写道:


....

更正
On Tue, 13 Apr 2004 07:20:06 GMT, Steve Jorgensen <no****@nospam.nospam>
wrote:

....
Correction
通常用VBA等语言模拟继承的方式是
Concrete类封装(包含对Abstract类的引用),并且
通过包装器方法为每个提供对Abstract类'成员的外部访问。对于我所描述的情况,这是一个完全混乱,这就是为什么
这种情况是如此的问题,需要这个解决方案;它添加了尽可能多的重复,因为它删除。每个Concrete类必须为Abstract类的每个公共成员(Concrete类 $>没有实现)。
The way inheritance is normally simulated in languages like VBA is that the
Concrete class encapsulates (contains a reference to) the Abstract class, and
provides external access to the Abstract class'' members via a wrapper method
for each. For the situation I''ve described, that''s a total mess, which is why
this case is such a prolem and in need of this solution; it adds as much
duplication as it removes. Every Concrete class has to implement and expose
all of its concrete members (that external code doesn''t need) plus a wrapper
for every single public member of the Abstract class (that the Concrete class
doesn''t implement).




我的目的是说它是标准解决方案,它可以添加尽可能多的重复b / b
删除,而不是我建议的解决方案添加了多少

重复删除< g> ;.



My intention was to say it is the standard solution that adds as much
duplication as it removes, not that my proposed solution adds as much
duplication as it removes <g>.


Steve Jorgensen< no *** *@nospam.nospam>写在

新闻:54 ******************************** @ 4ax.com:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:54********************************@4ax.com:
2004年4月13日星期二07:20:06 GMT,Steve Jorgensen
< no **** @ nospam.nospam>写道:

...
更正
On Tue, 13 Apr 2004 07:20:06 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:

...
Correction
通常用VBA等语言模拟继承的方式是Concrete类封装的(包含引用)
抽象类,并通过每个的包装方法提供对Abstract
类成员的外部访问。对于我已经描述的情况,这是一个完全混乱,这就是为什么这个案例是这样一个问题并且需要这个解决方案的原因;它添加了尽可能多的重复,因为它删除。每个Concrete类都必须实现
并公开其所有具体成员(外部代码不需要)以及
Abstract类的每个公共成员的包装器(即具体类没有实现)。
The way inheritance is normally simulated in languages like VBA is
that the Concrete class encapsulates (contains a reference to) the
Abstract class, and provides external access to the Abstract
class'' members via a wrapper method for each. For the situation
I''ve described, that''s a total mess, which is why this case is
such a prolem and in need of this solution; it adds as much
duplication as it removes. Every Concrete class has to implement
and expose all of its concrete members (that external code doesn''t
need) plus a wrapper for every single public member of the
Abstract class (that the Concrete class doesn''t implement).



我的意图是说它是标准的解决方案,因为它删除了很多重复,而不是我建议的解决方案添加
重复删除< g>。



My intention was to say it is the standard solution that adds as
much duplication as it removes, not that my proposed solution adds
as much duplication as it removes <g>.




我开始得到它,但我仍然陷入困境示例

实现。你为自己设定的任务看起来很简单。对我来说,这是我用b / b
方法所做的事情,但是它真的是一个非常复杂的DLookup(),但是增加了

的功能,它增加了价值,如果它已经不存在了吗?


我不确定你从这种复杂性中得到了什么价值。有多少

次你真的要做这种事吗?假设您正在使用ID字段

和值字段(变量?)的所有表格的

结构,那么我只是没有看到代码

复制将进来。从最简单的情况开始,我在签名后用代码结束




现在,这可以很容易地推广到基于任何标准(通过参数数组)返回任何字段

,假设您返回

一个字段。在我看来,它不会产生可怕的代码,但是你的b $ b最终会导致一个函数超载的参数将会非常特殊地传递给b $ b格式。这总是引导我在类模块的方向上,因为它可以很容易地记录更多的元素来获取准确数据的要求

it。


但是我仍然没有看到哪里需要基类然后

特定课程。


我非常非常经常简单地编写单行封装器函数

复杂类模块(最常见的是当我需要在
$ b中使用输出时$ b查询,不能直接引用类模块),而你的

示例具体类只有极少数的

属性/方法/成员。


所以,我只是没有看到这里的好处:


1.你的例子似乎更容易实现更多

直截了当的方式


2.我无法想到一个同样没有的例子

很简单。


Eac当您选择一个示例时,您选择表格交互作为您的

主题。我认为表格交互很容易处理。

的确,我在阅读你的代码时一直在思考,我有时会使用

表来映射表和数据之间的关系在那些

表中(表作为存储结构,它们本身驱动代码的行为;>表,不存储关于
$的数据b $ b应用程序的最终用户查看数据,但是使用的商店信息完全用于驱动代码操作
。这个

的最常见的例子,我相信很多人都使用过的是导入/导出数据时

你经常使用表格将一边的字段映射到

其他的字段。


现在,我得到了这种东西的一线潜力

with objects这不是通用的(比如表格),但是特定于特定应用程序的是
,但它们以多种方式使用。我们有一定数量的传递。封装

如果我们将一个类模块包装在一个通用的

表单中,我们可以使用它们。我们可以直接通过

封装类的表单类型属性公开

封装表单的属性,方法和成员(包括<的自定义属性/方法/成员br />
封装形式),同时还通过额外的属性/方法/成员增强了封装形式




它是'不是真正的继承,但它正是你所描述的,

因为它是倒置的,所以放置了抽象。作为包装者的课程
围绕具体的
class(在这种情况下,一个表单)。


现在,你可以用类模块做同样的事情,因为

你已经如图所示,在抽象的一个属性中, class

返回对具体的引用。上课。


所以,从结构层面来说,这对我来说是有道理的,但是你的具体例子有点破坏了我理解它的能力

很清楚。


当描述我上面所做的方式时,它听起来并非如此

earth-惊天动地。但是当你谈到使用纯类

模块(不是表格)时,我觉得它有价值。


对我来说是一个关键的突破这里想到了想要为很多完全相同类型的对象添加一堆行为和属性的想法。当我看到围绕一堆表格的概念时,为所有形式添加了新功能,这样就封装了形式,它开始变得有意义了。


但我认为谈论它好像是继承b兑b
是错误的。它实际上根本不是 - 它只是一种

封装形式,它给你带来与

相同的好处,消除了代码重复作为纯继承确实如此。


(当然,我也假设我终于明白了!)


-

David W. Fenton http://www.bway.net/~dfenton

dfenton at bway dot net http:// www.bway.net/~dfassoc

公共函数idLookup(strLookupValue为String,_

strLookupField为String,strLookupTable为String,_

可选ysnAdd As Boolean = True,_

可选db as DAO.Database)As Long

Dim ysnReleaseDB As Boolean

Dim strSQL As String

Dim rs As DAO.Recordset

Dim strIDField as String


如果db is Nothing那么

设置db = CurrentDb()

ysnReleaseDB = True

结束如果

strIDField = Mid(strLookupTable,4)& " ID"

strSQL =" SELECT" &安培; strLookupTable& "。" &安培; strIDField

strSQL = strSQL& , &安培; strLookupTable& "。" &安培; strLookupField

strSQL = strSQL& "来自 &安培; strLookupTable

strSQL = strSQL& "在哪里 &安培; strLookupTable& "。"

strSQL = strSQL& strLookupField& " =''"

strSQL = strSQL& strLookupValue& "'';"

设置rs = db.OpenRecordset(strSQL)

如果rs.RecordCount = 0那么

如果ysnAdd那么

rs.AddNew

rs(strLookupField)= strLookupValue

rs.Update

结束如果

结束如果

如果rs.RecordCount<> 0然后

rs.MoveFirst

idLookup = rs(strIDField)

结束如果


rs 。关闭

设置rs =没什么

如果ysnReleaseDB然后设置db = Nothing

结束功能



I''m beginning to get it, but I''m still bogged down in your example
implementation. The task you''ve set for yourself seems really simple
to me -- it''s the kind of thing I do all the time by various
methods, but it''s really a very elaborate DLookup(), but with the
added feature that it adds the value if it''s not there already?

I''m not sure what value you''ve gotten from this complexity. How many
times do you really have to do this kind of thing? Assuming a
structure for all your tables that you''re working with of ID field
and value field (variant?), then I just don''t see where the code
duplication would come in. Working up from the simplest case, I end
up with the code after my signature.

Now, that could easily be generalized to returning any field based
on any criteria (via a parameter array), assuming you are returning
one field. It wouldn''t produce horrid code, in my opinion, but you
would end up with a function overloaded with arguments that would
have to be passed in a very special format. That always leads me in
the direction of a class module, since that can document much more
easily what the requirements are for getting accurate data out of
it.

But I still don''t see where there needs to be a base class and then
specific classes.

I very, very often write simply one-line wrapper functions around
complex class modules (most often when I need to use the output in a
query, which can''t refer directly to class modules), and your
example concrete classes have only a very small number of
properties/methods/members.

So, I''m just not seeing where the benefit is here:

1. your example seems more easily implemented in a much more
straightforward manner

2. I''m not able to think of an example that isn''t likewise going to
be simple like that.

Each time you choose an example, you pick table interaction as your
subject. Table interactions are, I think, pretty easy to deal with.
Indeed, I kept thinking while reading your code that I sometimes use
tables to map relationships between tables and data within those
tables (tables as storage structures that themselves drive the
behavior of code; that is, tables that don''t store data about the
app''s end-user viewed data, but that store information that is used
entirely to drive code operation). The most common example of this
that I''m sure many people have used is when importing/exporting data
you often use a table to map fields on one side to fields on the
other.

Now, where I get a glimmer of potential for this kind of thing is
with objects that are not generic (like tables), but that are
specific to a particular application, but that are used in multiple
ways. We have a certain amount of "pass-through" encapsulation
available to us if we, say, wrap a class module around a generic
form. We can expose the properties, methods and members of the
encapsulated form directly through a form-type property of the
encapsulating class (including custom properties/methods/members of
the encapsulated form), while also enhancing the encapasulated form
with additional propertis/methods/members.

It''s not real inheritance, but it''s exactly what you''ve described,
in that it''s upside-down, placing the "abstract" class as a wrapper
around the "concrete" class (in this case, a form).

Now, you can do the same kind of thing with a class module, as
you''ve shown, in that one of the properties of the "abstract" class
returns a reference to the "concrete" class.

So, it sort of makes sense to me from a structural level, but your
specific examples are sort of sabotaging my ability to understand it
clearly.

And when described the way I''ve done above, it doesn''t sound so
earth-shattering. But when you talk about using it with pure class
modules (not forms), it does seem to me to have value.

The key breakthrough for me here was thinking about the idea of
wanting to add a bunch of behaviors and properties to a lot of
objects of exactly the same type. When I looked at the concept of a
wrapper around a bunch of forms that added new capabilities to all
the forms thus encapsulated, it began to make sense.

But I think it''s a mistake to talk about it as though it''s
inheritance. It really isn''t at all -- it''s just a form of
encapsulation that gives you the same benefits in regard to
eliminating code duplication as pure inheritance does.

(Of course, I''m also assuming that I''ve finally understood!)

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc

Public Function idLookup(strLookupValue As String, _
strLookupField As String, strLookupTable As String, _
Optional ysnAdd As Boolean = True, _
Optional db As DAO.Database) As Long
Dim ysnReleaseDB As Boolean
Dim strSQL As String
Dim rs As DAO.Recordset
Dim strIDField As String

If db Is Nothing Then
Set db = CurrentDb()
ysnReleaseDB = True
End If
strIDField = Mid(strLookupTable, 4) & "ID"
strSQL = "SELECT " & strLookupTable & "." & strIDField
strSQL = strSQL & ", " & strLookupTable & "." & strLookupField
strSQL = strSQL & " FROM " & strLookupTable
strSQL = strSQL & " WHERE " & strLookupTable & "."
strSQL = strSQL & strLookupField & "=''"
strSQL = strSQL & strLookupValue & "'';"
Set rs = db.OpenRecordset(strSQL)
If rs.RecordCount = 0 Then
If ysnAdd Then
rs.AddNew
rs(strLookupField) = strLookupValue
rs.Update
End If
End If
If rs.RecordCount <> 0 Then
rs.MoveFirst
idLookup = rs(strIDField)
End If

rs.Close
Set rs = Nothing
If ysnReleaseDB Then Set db = Nothing
End Function




" David W. Fenton" < DX ******** @ bway.net.invalid>在消息中写道

新闻:Xn ********************************** @ 24.168 .1 28.78 ...

"David W. Fenton" <dX********@bway.net.invalid> wrote in message
news:Xn**********************************@24.168.1 28.78...
Steve Jorgensen< no **** @ nospam.nospam>在
新闻中写道:54 ******************************** @ 4ax.com:
但是我觉得把它当成继承是错误的。它实际上根本不是 - 它只是一种
封装形式,在消除代码重复方面给你带来了与纯继承相同的好处。

(当然,我也假设我终于明白了!)
Steve Jorgensen <no****@nospam.nospam> wrote in
news:54********************************@4ax.com: But I think it''s a mistake to talk about it as though it''s
inheritance. It really isn''t at all -- it''s just a form of
encapsulation that gives you the same benefits in regard to
eliminating code duplication as pure inheritance does.

(Of course, I''m also assuming that I''ve finally understood!)




这是遏制。而已。没有更少。

一个对象将另一个对象实例化为成员变量,并且
在内部使用该对象属性和方法。这是遏制。

如果成员对象的属性和方法暴露在代码外的

,那将是委托。代表团是遏制

避免。将成员对象属性和方法公开给代码外部的
通常需要在包含类的

中添加属性和方法。这就是史蒂夫认为的代码重复。这不是
。这就是它的完成方式。


这篇msdn文章展示了一种扩展接口的方式/ b
要做的类大致相同的事情。对于那些不能生活和呼吸的人来说,在谷仓周围再一次,这是一个漫长的过程。

http://msdn.microsoft.com/library/ de ... lymorphism.asp






It''s containment. Nothing more. Nothing less.
One object instantiates another object as a member variable and
uses that objects properties and methods internally. It''s containment.
If the member object''s properties and methods were exposed to
outside code it would be delegation. Delegation is what containment
avoids. Exposing the member objects properties and methods to
outside code usually involves adding properties and methods to the
containing class. That is what Steve sees as code duplication. It''s
not. It''s just the way it''s done.

This msdn article shows a way to sort of/kind of extend interface
classes to do much the same thing. Once again it''s a long way
around the barn for people who don''t live and breath oop.

http://msdn.microsoft.com/library/de...lymorphism.asp






这篇关于尝试#2 - VBA中的继承解决方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆