473,770 Members | 1,899 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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 TestDataReaderA bc()
Dim objDataReader As clsDataReader

' With block creates temporary reference to a new
' clsDataReaderSe tupAbc object, then that is used to
' create and return a new clsDataReader object that
' now encapsulates the clsDataReaderSe tupAbc object,
' and uses it for metadata, etc.
With New clsDataReaderSe tupAbc
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 IDataReaderSetu p
Private mdbs As DAO.Database
Private mrst As DAO.Recordset

Public Sub Setup(objSetup As IDataReaderSetu p)
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.OpenRecord set("",strSql)
End Sub

Public Property Get DataItem() As Variant
DataItem = mrst.Fields(mob jSetup.FieldNam e).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
- IDataReaderSetu p
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
- clsDataReaderSe tupAbc (There could have many other Setup classes!)
Option Explicit

Implements IDataReaderSetu p

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

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

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

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

Nov 12 '05
20 23112
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bwa y.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.dabb a.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
understandin g 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.c om...
On Sat, 10 Apr 2004 02:52:55 GMT, "rkc" <rk*@yabba.dabb a.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.c om...
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bwa y.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.dabb a.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********@bwa y.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
implementation s 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.dabb a.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.dab ba.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.c om:
On Fri, 09 Apr 2004 19:25:15 GMT, "David W. Fenton"
<dX********@bw ay.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 counterintuitiv e 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********@bwa y.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********@b way.net.invalid > wrote:
Steve Jorgensen <no****@nospam. nospam> wrote in
news:3a***** *************** ************@4a x.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 counterintuitiv e 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.c om...
On Sat, 10 Apr 2004 14:27:45 GMT, "rkc" <rk*@yabba.dabb a.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.dab ba.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.dabb a.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.dab ba.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.dab ba.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
Jorgentainme nt 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

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

Similar topics

20
5247
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 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...
61
3285
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 and again. I know to remove code-duplication I have to make functions and pass arguments to them but I am not able to think of a way doing it. Can you post some example for me, out of this code:
0
9617
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10099
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10036
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9904
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
6710
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5354
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
4007
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3607
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2849
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.