473,326 Members | 2,081 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,326 software developers and data experts.

Faking inheritance in VBA to remove code duplication

A while back, I started boning up on Software Engineering best practices and
learning about Agile programming. In the process, I've become much more
committed to removing duplication in code at a much finer level. As such,
it's very frustrating to be working in VBA which lacks inheritance, one of the
more powerful tools for eliminating duplication at the level I'm talking
about.

I've recently come up with a technique to emulate one special case of
inheritance that's handy in an awful lot of cases.

First off, yes, it's true that you can just simulate inheritance using
encapsulation, but then you have to add members to every single encapsulating
class to wrap every single public member of the encapsulated class. Each time
you add a member to the "base class" you have to meticulously update all the
"inheriting" classes as well.

So, here's my alternative for one common use case of inheritance. Note that
this is made more useful since other cases of inheritance can be force-fit
into this model. If this is too much to swallow cold, try looking at the code
example at the end, then come back to the text. The code is simpler than the
explanation.

First, the case I'm talking about is where the base class provides functions
and interfaces that are mutable primarily in terms of the metadata they use to
do their jobs. It is not enough, however, to simply initialize an instance
with a data structure, though, because not all the metadata is constant, or
one would not want to count on that being a permanent situation. In a typical
OOP language, this would be done by having private virtual members in the base
class that would be overridden by the inheriting class to supply data to the
base class.

Now, the model. I call this model the "Setup Class" model. It's sort of a
cross between a factory model and a decorator class. Instead of having the
"base class" contained in the "inheriting class", it's the other way around,
but the "inheriting class" (the Setup class) is what the external code creates
first, then uses that as sort of a factory for its base class which is then
stored by the external code, and now encapsulates the Setup class which now
provides the metadata for the Base class.
A simplified code example follows. This is air code, but I have similar code
in production. In my production system, I have one setup object for the
production database, and one for a testing database. The pre-setup for the
testing database makes a new copy from a template, so it is always in a known
state before the download begins. The production database has no pre-setup
action (like this example)...
- Usage example
Option Explicit

Public Sub TestDataReaderAbc()
Dim objDataReader As clsDataReader

' With block creates temporary reference to a new
' clsDataReaderSetupAbc object, then that is used to
' create and return a new clsDataReader object that
' now encapsulates the clsDataReaderSetupAbc object,
' and uses it for metadata, etc.
With New clsDataReaderSetupAbc
Set objDataReader = .GetReader()
End With

With objDataReader
While Not .EndOfData
Debug.Print .DataItem
.NextItem
Wend
End With

End Sub
- clsDataReader
Option Explicit

Private mobjSetup As IDataReaderSetup
Private mdbs As DAO.Database
Private mrst As DAO.Recordset

Public Sub Setup(objSetup As IDataReaderSetup)
Dim strSql As String
Set mobjSetup = objSetup
With mobjSetup
.PreSetup
Set mdbs = CurrentDb
strSql = "SELECT " & .FieldName & _
" FROM " & .TableName & _
" ORDER BY " & .FieldName
End With
Set mrst = mdbs.OpenRecordset("",strSql)
End Sub

Public Property Get DataItem() As Variant
DataItem = mrst.Fields(mobjSetup.FieldName).Value
End Property

Public Sub NextItem()
mrst.MoveNext
End Property

Public Property Get EndOfData() As Boolean
EndOfData = mrst.EOF
End Property

Private Sub Class_Terminate()
If Not (mrst Is Nothing) Then
mrst.Close: Set mrst = nothing
End If
Set mdbs = Nothing
End Sub
- IDataReaderSetup
Option Explicit

Public Sub PreSetup() As clsDataReader
End Function

Public Function GetDataReader() As clsDataReader
End Function

Public Property Get TableName() As String
End Property

Public Property Get FieldName() As String
End Property
- clsDataReaderSetupAbc (There could have many other Setup classes!)
Option Explicit

Implements IDataReaderSetup

Public Sub IDataReaderSetup_PreSetup() As clsDataReader
' No pre-setup actions required for this Setup class
End Function

Private Function IDataReaderSetup_GetDataReader() As clsDataReader
Dim objResult As New clsDataReader
objResult.Setup Me
Set GetDataReader = objResult
End Function

Private Property Get IDataReaderSetup_TableName() As String
TableName = "tblTest"
End Property

Private Property Get IDataReaderSetup_FieldName() As String
TableName = "ItemName"
End Property

Nov 12 '05 #1
20 23038
Steve Jorgensen <no****@nospam.nospam> wrote in
news:mp********************************@4ax.com:

[a lot that I'm not sure I understood]

Uh, what are you getting out of this that simply exposing your
recordset variable as a public member won't accomplish?

That is, aren't you just recreating properties of the recordset
class in your wrapper class?

We discussed this kind of thing long ago when I posted about my
recordset wrapper class (code posted below sig -- note this is a
specific implementation where I was navigating a large totals
recordset).

How is what you're doing better than what I was suggesting?

(indeed, yours doesn't even allow the use of dynamic SQL)

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
clRecordsetWrapper
------------------
Option Compare Database
Option Explicit

Private db As Database
Private rs As Recordset ' THIS COULD BE MADE PUBLIC
Private strSQL As String
Private strCriteria As String
Private strReturnField As String

Public Property Let SQL(pstrSQL As String)
On Error GoTo err_SQL

strSQL = pstrSQL
'Debug.Print strSQL
Set rs = db.OpenRecordset(strSQL)

exit_SQL:
Exit Property

err_SQL:
MsgBox Err.Number & ": " & Err.Description, vbExclamation, _
"Error in clRecordSetWrapper.SQL Property Let"
Resume exit_SQL
End Property

Public Property Get SQL() As String
SQL = strSQL
End Property

Public Function GetValue(pstrCriteria As String, _
pstrReturnField As String) As Variant
strCriteria = pstrCriteria
strReturnField = pstrReturnField
If rs.RecordCount <> 0 Then
rs.FindFirst strCriteria
If Not rs.NoMatch Then
GetValue = rs(strReturnField)
End If
End If
End Function

Public Function GetNextValue(Optional pstrReturnField As String) _
As Variant
If Len(strCriteria) = 0 Then
MsgBox "You must call GetValue before you can call _
GetNextValue", vbExclamation, _
"Error in clRecordSetWrapper.GetNextValue()"
Exit Function
End If
If Len(pstrReturnField) > 0 Then strReturnField = pstrReturnField
If rs.RecordCount <> 0 Then
rs.FindNext strCriteria
If Not rs.NoMatch Then
GetNextValue = rs(strReturnField)
End If
End If
End Function

Private Sub Class_Initialize()
Set db = CurrentDb()
End Sub

Private Sub Class_Terminate()
rs.Close
Set rs = Nothing
Set db = Nothing
End Sub

Public Property Get GetTotal(pstrCriteria As String, _
pstrReturnField As String) As Double
Dim dblTotal As Double

If rs.RecordCount <> 0 Then
rs.FindFirst pstrCriteria
Do Until rs.NoMatch
If Not IsNull(rs(pstrReturnField)) Then
dblTotal = dblTotal + rs(pstrReturnField)
End If
rs.FindNext pstrCriteria
If rs.EOF Then Exit Do
Loop
End If
GetTotal = dblTotal
End Property
Nov 12 '05 #2
On Wed, 07 Apr 2004 18:29:18 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:mp********************************@4ax.com :

[a lot that I'm not sure I understood]

Uh, what are you getting out of this that simply exposing your
recordset variable as a public member won't accomplish?
Not much - I guess that's the problem with simplified examples. It makes more
sense when the reader is handling a business object model more complex than a
single recordset.
That is, aren't you just recreating properties of the recordset
class in your wrapper class?
It my real-world case, there are several recordsets involved, and the class
encapsulates the logic of reading and writing related values while providing a
clear, simple API to the external code.
We discussed this kind of thing long ago when I posted about my
recordset wrapper class (code posted below sig -- note this is a
specific implementation where I was navigating a large totals
recordset).
I remember having that discussion, though not the specifics - I'll review
that.
How is what you're doing better than what I was suggesting?

(indeed, yours doesn't even allow the use of dynamic SQL)


The purpose of this pattern is not to allow things like dynamic SQL, and its
advantages don't have to do with being general-purpose. This is intended to
be a design pattern applied individually to specific cases, and not a reusable
library routine itself.

The goal of this pattern is to remove duplication in a specific application,
so that the majority of the code in the Setup class has -only- to do with what
makes that case unique, and has almost nothing to do with what's common to all
cases. The common code goes in the "base" class and is kept in one place,
never duplicated, and not subject to errors that can arise later in
maintaining code that contains such duplication.

I'll review the earlier thread tomorrow, and possobly post another reply. It
could be that your suggestion id better than what I'm suggesting here, but I
perhaps didn't have the context to apply it right away at the time. It's also
likely that what we have are 2 different answers to 2 different issues.

Nov 12 '05 #3
rkc

"David W. Fenton" <dX********@bway.net.invalid> wrote in message
news:Xn**********************************@24.168.1 28.86...
Steve Jorgensen <no****@nospam.nospam> wrote in
news:mp********************************@4ax.com:

[a lot that I'm not sure I understood]

Uh, what are you getting out of this that simply exposing your
recordset variable as a public member won't accomplish?

That is, aren't you just recreating properties of the recordset
class in your wrapper class?

We discussed this kind of thing long ago when I posted about my
recordset wrapper class (code posted below sig -- note this is a
specific implementation where I was navigating a large totals
recordset).

How is what you're doing better than what I was suggesting?


His point wasn't about wrapping a recordset. It was about
using a base class that didn't change to do similar, but
different things via a setup class. The setup class is
implemented using an interface so that even though there
may be multiple setup classes each one is accessed using
the same methods and properties expected by the base class.

His example was too simple to illustrate any advantage(s)
there may be in going that far around the barn while using
VBA. Someone who develops applications alone is probably
less likely to go that route, or even explore it, than someone
who often finds themselves working with others.

That's my take. I could be full of crap.

Nov 12 '05 #4
On Fri, 09 Apr 2004 02:31:15 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"David W. Fenton" <dX********@bway.net.invalid> wrote in message
news:Xn**********************************@24.168. 128.86...
Steve Jorgensen <no****@nospam.nospam> wrote in
news:mp********************************@4ax.com:

[a lot that I'm not sure I understood]

Uh, what are you getting out of this that simply exposing your
recordset variable as a public member won't accomplish?

That is, aren't you just recreating properties of the recordset
class in your wrapper class?

We discussed this kind of thing long ago when I posted about my
recordset wrapper class (code posted below sig -- note this is a
specific implementation where I was navigating a large totals
recordset).

How is what you're doing better than what I was suggesting?


His point wasn't about wrapping a recordset. It was about
using a base class that didn't change to do similar, but
different things via a setup class. The setup class is
implemented using an interface so that even though there
may be multiple setup classes each one is accessed using
the same methods and properties expected by the base class.

His example was too simple to illustrate any advantage(s)
there may be in going that far around the barn while using
VBA. Someone who develops applications alone is probably
less likely to go that route, or even explore it, than someone
who often finds themselves working with others.

That's my take. I could be full of crap.


You have correctly sussed my intent, though I must say, my rambling
explanation probably wasn't much help. I also realized later that since the
external code must explicitly refer to both the "Base" and "Setup" classes,
that it was not right to call a Get<Base> method of the "Setup" class that
does nothing more than pass itself to the Setup method of the "Base" class.
That just ends up requiring duplication of the setup code in every "Setup"
class for no good reason.

When I turn that around, and simply make the external code make a "Setup"
class, and pass it to the "Base" class, I end up not having a "Setup" pattern
at all, but the previously well-documented "Template" pattern. It just so
happens that this works out in VBA since it is a pattern that does not rely in
implementation inheritance - cool. The benefit is more obvious (and more so)
with this fix in place.

Here's the fixed-up example. I'm still not totally clear which part is
supposed to be the Template in the "Template" pattern, so forgive me (and
correct me if possible) if the naming is inside out...

- Usage example
Option Explicit

Public Sub TestDataReaderAbc()
Dim objDataReader As clsDataReader

Set objDataReader = New clsDataReader
objDataReader.Setup New clsDataReaderSetupAbc

With objDataReader
While Not .EndOfData
Debug.Print .DataItem
.NextItem
Wend
End With

End Sub
- clsDataReader
Option Explicit

Private mobjSetup As IDataReaderTemplate
Private mdbs As DAO.Database
Private mrst As DAO.Recordset

Public Sub Setup(objSetup As IDataReaderTemplate)
Dim strSql As String
Set mobjSetup = objSetup
With mobjSetup
.PreSetup
Set mdbs = CurrentDb
strSql = "SELECT " & .FieldName & _
" FROM " & .TableName & _
" ORDER BY " & .FieldName
End With
Set mrst = mdbs.OpenRecordset("",strSql)
End Sub

Public Property Get DataItem() As Variant
DataItem = mrst.Fields(mobjSetup.FieldName).Value
End Property

Public Sub NextItem()
mrst.MoveNext
End Property

Public Property Get EndOfData() As Boolean
EndOfData = mrst.EOF
End Property

Private Sub Class_Terminate()
If Not (mrst Is Nothing) Then
mrst.Close: Set mrst = nothing
End If
Set mdbs = Nothing
End Sub
- IDataReaderTemplate
Option Explicit

Public Sub PreSetup() As clsDataReader
End Function

Public Property Get TableName() As String
End Property

Public Property Get FieldName() As String
End Property
- clsDataReaderTemplateAbc (One could have many other Template classes)
Option Explicit

Implements IDataReaderTemplate

Public Sub IDataReaderTemplate_PreSetup() As clsDataReader
' No pre-setup actions required for this Setup class
End Function

Private Property Get IDataReaderTemplate_TableName() As String
TableName = "tblTest"
End Property

Private Property Get IDataReaderTemplate_FieldName() As String
TableName = "ItemName"
End Property

Nov 12 '05 #5
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:1r********************************@4ax.com...
On Fri, 09 Apr 2004 02:31:15 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb> wrote:

When I turn that around, and simply make the external code make a "Setup"
class, and pass it to the "Base" class, I end up not having a "Setup" pattern at all, but the previously well-documented "Template" pattern. It just so
happens that this works out in VBA since it is a pattern that does not rely in implementation inheritance - cool. The benefit is more obvious (and more so) with this fix in place.

Here's the fixed-up example. I'm still not totally clear which part is
supposed to be the Template in the "Template" pattern, so forgive me (and
correct me if possible) if the naming is inside out...


It's early, but all I see is a basic use of containment. I think that if
either class
were to be considered a template in this situation it would be the setup
class.
Nov 12 '05 #6
On Fri, 09 Apr 2004 11:32:03 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:1r********************************@4ax.com.. .
On Fri, 09 Apr 2004 02:31:15 GMT, "rkc"

<rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

When I turn that around, and simply make the external code make a "Setup"
class, and pass it to the "Base" class, I end up not having a "Setup"

pattern
at all, but the previously well-documented "Template" pattern. It just so
happens that this works out in VBA since it is a pattern that does not

rely in
implementation inheritance - cool. The benefit is more obvious (and more

so)
with this fix in place.

Here's the fixed-up example. I'm still not totally clear which part is
supposed to be the Template in the "Template" pattern, so forgive me (and
correct me if possible) if the naming is inside out...


It's early, but all I see is a basic use of containment. I think that if
either class
were to be considered a template in this situation it would be the setup
class.


A template is a simple example of containment, but it's what the containment
is used for and how it is used to supstitute for a kind of inheritance that
makes it so useful. Before I had this pattern, I was trying to have the
"Template" be the container, but then there's not enough benefit to make it
worthwhile, since you have to make a forwarding stub method for every method
in the base class.
Nov 12 '05 #7
On Fri, 09 Apr 2004 15:24:19 GMT, Steve Jorgensen <no****@nospam.nospam>
wrote:
On Fri, 09 Apr 2004 11:32:03 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:1r********************************@4ax.com. ..
On Fri, 09 Apr 2004 02:31:15 GMT, "rkc"

<rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

When I turn that around, and simply make the external code make a "Setup"
class, and pass it to the "Base" class, I end up not having a "Setup"

pattern
at all, but the previously well-documented "Template" pattern. It just so
happens that this works out in VBA since it is a pattern that does not

rely in
implementation inheritance - cool. The benefit is more obvious (and more

so)
with this fix in place.

Here's the fixed-up example. I'm still not totally clear which part is
supposed to be the Template in the "Template" pattern, so forgive me (and
correct me if possible) if the naming is inside out...


It's early, but all I see is a basic use of containment. I think that if
either class
were to be considered a template in this situation it would be the setup
class.


A template is a simple example of containment, but it's what the containment
is used for and how it is used to supstitute for a kind of inheritance that
makes it so useful. Before I had this pattern, I was trying to have the
"Template" be the container, but then there's not enough benefit to make it
worthwhile, since you have to make a forwarding stub method for every method
in the base class.


Well, dang. I just did some more research, and I don't think this is quite
the "Template" method either, nor quite the "Strategy" pattern, but it's kind
of like those. It seems like this must be a documented pattern, but I can't
figure out which one.

It turns out the Template pattern is about allowing the inheriting class to be
able to insert functionality at the beginning and/or end of an operation
implemented in the base class. A perfect example of this is the BeforeUpdate
and AfterUpdate event handlers in Access form modules.

If it were the Strategy pattern, the "Base" class would be called the Abstract
class, and the "Inheriting" classes would be called "Concrete" classes. In
that metaphor, though, the Template class would usually be very light, and
most of the implementation would belong to the Concrete classes (like using a
Socket API (abstract) for a communication protocol (concrete)). Otherwise,
that's close.

The "Entity" design pattern
(http://www.codeproject.com/gen/desig...ignpattern.asp) also looks
close, but also seems not quite right. I can see how what I'm starting with
might evolve to look the Entity design pattern as the application is fleshed
out.

I guess I'm still not sure what pattern I'm describing, but I do think it's a
very useful pattern in VBA and solves some problems one would normally think
of using inheritance to solve in a true OOP language.
Nov 12 '05 #8
Steve Jorgensen <no****@nospam.nospam> wrote in
news:3a********************************@4ax.com:
I guess I'm still not sure what pattern I'm describing, but I do
think it's a very useful pattern in VBA and solves some problems
one would normally think of using inheritance to solve in a true
OOP language.


I simply can't separate the abstract part of your example from the
specific type of object you're encapsulating.

Can you do this with something other than a recordset?

For instance: I use dialog forms to collect criteria for filtering
reports and forms. What if one had a generic GetCriteria class that
was a wrapper around specific classes that encapsulated particular
dialog forms? Let's ignore for a moment that this is three levels of
classes (the form is itself a class), because your recordset example
also had that characteristic (which is perhaps why I was thrown
off).

My concept here is that you'd use a single GetCriteria class with a
fixed interface to utilize all the dialog forms for collecting
criteria.

I assume that's what you're trying to do, no?

My problem here is how you avoid duplication -- how do you enumerate
the properties and methods and members of the particular dialog
class via the generic class without setting up a bunch of interfaces
to custom private collections?

Or do I have the whole thing turned upside down here?

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #9
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:3a********************************@4ax.com...
I guess I'm still not sure what pattern I'm describing, but I do think it's a very useful pattern in VBA and solves some problems one would normally think of using inheritance to solve in a true OOP language.


That's the thing about design patterns. You really have to have a complete
understanding of the types of problems each one addresses before you
can recognize that the problem you face already has a solution.

I think you would need to explain more about the meta-data concept that
you mentioned before I can see what you have described as anything other
than using two of three methods available in VBA to simulate inheritance.
Nov 12 '05 #10
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:3a********************************@4ax.com :
I guess I'm still not sure what pattern I'm describing, but I do
think it's a very useful pattern in VBA and solves some problems
one would normally think of using inheritance to solve in a true
OOP language.
I simply can't separate the abstract part of your example from the
specific type of object you're encapsulating.


Basically, the abstract part is the part that's doing the DAO calls and
providing the SQL string templates since these to not differ for any cases I
have yet needed to employ. The specific classes provide just the metadata and
behavior that's different between the cases. In my real-world scenario, the
specific classes have methods that provide connect string, table names, field
names, pre-initialization behavior (the test case copies a new MDB from a
template file), and a description of the case, so the UI can show the
description, and remind the forgetful programmer which one he is using to
avoid doh! errors.
Can you do this with something other than a recordset?
Yes. It is useful in any case where the abstract class should provide much of
the implementation to avoid duplicating it in the specific classes, and the
details are metadata and actions meaningful to the abstract class, but the
external code doesn't usually want or need to interact with those directly.
In my case, the description is an exception since the external code does
interrogate that directly from the specific class instance before passing the
instance to the abstract class.
For instance: I use dialog forms to collect criteria for filtering
reports and forms. What if one had a generic GetCriteria class that
was a wrapper around specific classes that encapsulated particular
dialog forms? Let's ignore for a moment that this is three levels of
classes (the form is itself a class), because your recordset example
also had that characteristic (which is perhaps why I was thrown
off).

My concept here is that you'd use a single GetCriteria class with a
fixed interface to utilize all the dialog forms for collecting
criteria.

I assume that's what you're trying to do, no?
I actually can't tell if that's the same as what I'm saying or not. I think
it's not. There might be a cool way to solve that with classes and
abstractions, but I'm guessing it'll be a different pattern.
My problem here is how you avoid duplication -- how do you enumerate
the properties and methods and members of the particular dialog
class via the generic class without setting up a bunch of interfaces
to custom private collections?


If I get what you're saying, in a language without introspection (and VB has
no introspection), you can either have collections of items or you can have
individual methods to get the individual items, and the only way to have both
is to have duplication. From what I'm reading, the "right" answer in this
case is to use code to generate code, so the meta-code, the "source" code has
no duplication. The duplication in the generated code can be ignored, since
it's really just like a compilation stage at that point.

I think that's what I was aimimg for in our last heavy thread, and I never did
come up with a solution I was satisfied with, but I think it should be doable.
I'm getting better at thinking about these things, so I might come up with a
clean solution, if I make another stab at it now.

Nov 12 '05 #11
On Sat, 10 Apr 2004 02:52:55 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:3a********************************@4ax.com.. .
I guess I'm still not sure what pattern I'm describing, but I do thinkit's a
very useful pattern in VBA and solves some problems one would normally

think
of using inheritance to solve in a true OOP language.


That's the thing about design patterns. You really have to have a complete
understanding of the types of problems each one addresses before you
can recognize that the problem you face already has a solution.


Yeah, I'm starting to feel really silly sometimes about the time I've wasted
on something I could have found in on-line in 10 or 20 minutes of searching if
I knew to look for "design pattern ..."
I think you would need to explain more about the meta-data concept that
you mentioned before I can see what you have described as anything other
than using two of three methods available in VBA to simulate inheritance.


One problem I'm realizing is that design patterns are idealized, and aren't
really intended to be used unmodified in most real-world situations. Knowing
the design pattern gives you ammunition, but you devaite as appropriate.

In my case, the PreInitialize function makes it look a little like a Template
Function pattern, and the meta-data looks a little bit like an Entity pattern,
but an Entity would not usually do much more than validation and parsing.
Eventually, my app would probably end up having a true entity layer on the
front, the ADO wrapper? much like my current abstract object, would have the
DAO calls and SQL templates, and there might be yet another object at that
level that interfaces with something that's not even a database. Perhaps, it
would also have metadata? encapsualted objects, or perhaps, there would not be
multiple cases to need them... and so it grows.
Nov 12 '05 #12
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:fo********************************@4ax.com...
On Sat, 10 Apr 2004 02:52:55 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb> wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:3a********************************@4ax.com.. .
In my case, the PreInitialize function makes it look a little like a Template Function pattern, and the meta-data looks a little bit like an Entity pattern, but an Entity would not usually do much more than validation and parsing.


I'm leaning towards it looking somewhat like a Visitor pattern at the
moment.

Whadda'ya think?


Nov 12 '05 #13
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:o8********************************@4ax.com...
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:

I simply can't separate the abstract part of your example from the
specific type of object you're encapsulating.
Basically, the abstract part is the part that's doing the DAO calls and
providing the SQL string templates since these to not differ for any cases

I have yet needed to employ. The specific classes provide just the metadata and behavior that's different between the cases. In my real-world scenario, the specific classes have methods that provide connect string, table names, field names, pre-initialization behavior (the test case copies a new MDB from a
template file), and a description of the case, so the UI can show the
description, and remind the forgetful programmer which one he is using to
avoid doh! errors.


This is confusing. An abstract class is one that can not be instantiated. It
must be inherited and is usually meant to be extended. In VBA that
means an Interface. Your DataReaderSetup classes would be the
implementations of your abstract interface. Your abstraction is the
meta-data supplied by your setup classes to the single implementation
of your reader class.

That's my take. I could be full of crap.


Nov 12 '05 #14
On Sat, 10 Apr 2004 16:37:19 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:o8********************************@4ax.com.. .
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
>
>I simply can't separate the abstract part of your example from the
>specific type of object you're encapsulating.


Basically, the abstract part is the part that's doing the DAO calls and
providing the SQL string templates since these to not differ for any cases

I
have yet needed to employ. The specific classes provide just the metadata

and
behavior that's different between the cases. In my real-world scenario,

the
specific classes have methods that provide connect string, table names,

field
names, pre-initialization behavior (the test case copies a new MDB from a
template file), and a description of the case, so the UI can show the
description, and remind the forgetful programmer which one he is using to
avoid doh! errors.


This is confusing. An abstract class is one that can not be instantiated. It
must be inherited and is usually meant to be extended. In VBA that
means an Interface. Your DataReaderSetup classes would be the
implementations of your abstract interface. Your abstraction is the
meta-data supplied by your setup classes to the single implementation
of your reader class.

That's my take. I could be full of crap.


What you are saying is, strictly speaking, True, and I'm fudging the meaning
of abstract. In this case, my "Abstract" class can be instantiated, but it
cannot function until it is given the concrete class that provides the
necessary metadata for it to work. If this were C++, I would have use
protected, virtual functions in the base class that the inheriting class would
override to provide metadata, etc. Then my "Abstract" class would be an
Abstract class.
Nov 12 '05 #15
On Sat, 10 Apr 2004 14:27:45 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:fo********************************@4ax.com.. .
On Sat, 10 Apr 2004 02:52:55 GMT, "rkc"

<rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:
>
>"Steve Jorgensen" <no****@nospam.nospam> wrote in message
>news:3a********************************@4ax.com.. .

In my case, the PreInitialize function makes it look a little like a

Template
Function pattern, and the meta-data looks a little bit like an Entity

pattern,
but an Entity would not usually do much more than validation and parsing.


I'm leaning towards it looking somewhat like a Visitor pattern at the
moment.

Whadda'ya think?


Hmm, I think a Visitor as something that's used to perform a specific
operation on a collection, not something that's permanently embedded in
another object to specify some details of its behavior. For instance, I have
a function that compares 2 collections, and it has an optional parameter of
type IComparator that has a method called .IsEqual(var1 As Variant, var2 As
Variant). That way, you can pass an object to the function that compares the
collections to tell it what Equal means for the items in the collection to be
compared.
Nov 12 '05 #16
Steve Jorgensen <no****@nospam.nospam> wrote in
news:o8********************************@4ax.com:
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:3a********************************@4ax.co m:
I guess I'm still not sure what pattern I'm describing, but I do
think it's a very useful pattern in VBA and solves some problems
one would normally think of using inheritance to solve in a true
OOP language.


I simply can't separate the abstract part of your example from the
specific type of object you're encapsulating.


Basically, the abstract part is the part that's doing the DAO
calls and providing the SQL string templates since these to not
differ for any cases I have yet needed to employ.


The part where I get lost is where you refer to a class that has a
hard-wired SQL string in it as abstract. In my world, that's as
concrete as you get.

You're using "abstract," it seems to me, for the part of your code
that is shared by all the classes, in this case, your setup class.
Calling it abstract is so counterintuitive to me as to hopelessly
confuse my thinking on the whole thing that I can't get any further.

I can't say that I have a clue what you're trying to accomplish.

At least, I can't reconcile the code you've posted with what I
understand to be your goals.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 12 '05 #17
On Sat, 10 Apr 2004 20:16:07 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:o8********************************@4ax.com :
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:3a********************************@4ax.com :

I guess I'm still not sure what pattern I'm describing, but I do
think it's a very useful pattern in VBA and solves some problems
one would normally think of using inheritance to solve in a true
OOP language.

I simply can't separate the abstract part of your example from the
specific type of object you're encapsulating.
Basically, the abstract part is the part that's doing the DAO
calls and providing the SQL string templates since these to not
differ for any cases I have yet needed to employ.


The part where I get lost is where you refer to a class that has a
hard-wired SQL string in it as abstract. In my world, that's as
concrete as you get.

You're using "abstract," it seems to me, for the part of your code
that is shared by all the classes, in this case, your setup class.
Calling it abstract is so counterintuitive to me as to hopelessly
confuse my thinking on the whole thing that I can't get any further.


Fair enough - read my reply to RKC on that same point to see where I was
coming from when I used that term.
I can't say that I have a clue what you're trying to accomplish.
At least, I can't reconcile the code you've posted with what I
understand to be your goals.


To me, that means I've probably failed to communicate well. Take another
looking at the last code example update, ignore my misuses of terms, and see
if that makes the intention more clear. My primary goal is to minimize
duplication, regardless of how badly I've mangled anything else about my
explanation.

I'll take another stab at it this today or tomorrow, and see if I can describe
what I'm doing in decipherable language.
Nov 12 '05 #18
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:ei********************************@4ax.com...
On Sat, 10 Apr 2004 14:27:45 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb> wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:fo********************************@4ax.com.. .
On Sat, 10 Apr 2004 02:52:55 GMT, "rkc"<rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:
I'm leaning towards it looking somewhat like a Visitor pattern at the
moment.

Whadda'ya think?


Hmm, I think a Visitor as something that's used to perform a specific
operation on a collection, not something that's permanently embedded in
another object to specify some details of its behavior. For instance, I

have a function that compares 2 collections, and it has an optional parameter of type IComparator that has a method called .IsEqual(var1 As Variant, var2 As Variant). That way, you can pass an object to the function that compares the collections to tell it what Equal means for the items in the collection to be compared.


A Visitor is a object specifically created to provide a function for another
specific object that the object doesn't provide for itself. A Visitor has
to
know enough about the object it visits to do it's job and the visited object
must know enough to accept the visitor. The fact that you can visit a
collection of objects is just a use of the visitor pattern not part of the
pattern. That's my take. I may be full...

Any who.. I guess I was sorta reaching for that one. I think I'll drop back
to seeing it as a standard use of containment. Maybe you can name it the
Jorgentainment Pattern.



Nov 12 '05 #19
On Sun, 11 Apr 2004 03:41:45 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:ei********************************@4ax.com.. .
On Sat, 10 Apr 2004 14:27:45 GMT, "rkc"<rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:
>
>"Steve Jorgensen" <no****@nospam.nospam> wrote in message
>news:fo********************************@4ax.com.. .
>> On Sat, 10 Apr 2004 02:52:55 GMT, "rkc"
><rk*@yabba.dabba.do.rochester.rr.bomb>
>> wrote: >I'm leaning towards it looking somewhat like a Visitor pattern at the
>moment.
>
>Whadda'ya think?


Hmm, I think a Visitor as something that's used to perform a specific
operation on a collection, not something that's permanently embedded in
another object to specify some details of its behavior. For instance, I

have
a function that compares 2 collections, and it has an optional parameter

of
type IComparator that has a method called .IsEqual(var1 As Variant, var2

As
Variant). That way, you can pass an object to the function that compares

the
collections to tell it what Equal means for the items in the collection to

be
compared.


A Visitor is a object specifically created to provide a function for another
specific object that the object doesn't provide for itself. A Visitor has
to
know enough about the object it visits to do it's job and the visited object
must know enough to accept the visitor. The fact that you can visit a
collection of objects is just a use of the visitor pattern not part of the
pattern. That's my take. I may be full...


The examples I can find of visitors seem to deal with operations (such as
compare) applied to 2 or more other object instances. I suppose the examples
could be overly specific.
Any who.. I guess I was sorta reaching for that one. I think I'll drop back
to seeing it as a standard use of containment. Maybe you can name it the
Jorgentainment Pattern.


I did some more research, and the closest thing I can find to the pattern I
actually used seems to be the Template method pattern, but mine really does
seem to be a unique variation on that pattern that can work without
inheritance. I might not be the first to come up with it, but the only other
documentation I can identify on VB/VBA specific patterns is in a book I don't
yet have, and not freely available on-line.

If inheritance was available/used, the external code would not have to
instantiate the "Concrete" class, and that class would inherit from the
"Abstract" class rather than being encapsulated within it. Also, in the
Template Method pattern, one or more methods in the Concrete class might be
accessible to the external code via inheritance of virtual public methods in
the "Abstract" class without the need for any code in the Abstract class,
whereas in my variation, the external code either needs to access such methods
directly from the "Concrete" class or via wrapper functions added to the
"Abstract" class.

Nov 12 '05 #20
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:i6********************************@4ax.com...

The examples I can find of visitors seem to deal with operations (such as
compare) applied to 2 or more other object instances. I suppose the examples could be overly specific.


At the risk of boring you to death (but hey, you started this) take a look
at
this (C# implementation)

http://www.dofactory.com/patterns/PatternVisitor.aspx
Nov 12 '05 #21

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

20
by: Steve Jorgensen | last post by:
A while back, I started boning up on Software Engineering best practices and learning about Agile programming. In the process, I've become much more committed to removing duplication in code at a...
61
by: arnuld | last post by:
I have created a program which creates and renames files. I have described everything in comments. All I have is the cod-duplication. function like fopen, sprint and fwrite are being called again...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.