The classing Visual Basic and VBA support for polymorphism, let's face it, is
a bit on the weak side, and built-in support for inheritance is non-existent.
This little essay is about some patterns I've ended up using successfully for
certain kinds of inheritance and polymorphism, and some that have not worked
out so well.
Let's start with obvious things that turn out not to work well:
1. Use interface classes and "Implements" for polymorphism:
At first glance, this seems like a fine choice. After all, in languages like
Java, interface implementation is used by most programmers at least as often
as inheritance, and is better than inheritance for many things. Also, using
interfaces allows for polymorphism without breaking type safety. Alas, in VB
things are not as good as they at first appear.
As it turns out, interfaces and Implements are useful sometimes in limited
circumstances, but the way they work in VB makes them often take extra effort
to maintain and makes them behave unpredictably in many circumstances.
First of all, rather than simply requiring that all the interface members be
implemented and making them visible through the interface like Java would do,
VB requries you to explicitly create an implementation of each method for each
interface using a qualified name. Each of these is then a separate method
that can its own different implementation (oh what a tangled web that could
be), and to make all cases act the same (like you want about 100% of the
time), you must explicitly call one central method from each of the interface
implementations fo the case.
Now, if that weren't bad enough, you'd best be careful never to mix early
binding and late binding code on the same classes in the wrong order because
if you set an Object variable equal to a variable of an interface type, the
object behaves as an instance of the interface it was in before you assigned
it. In other words, even though it is now housed in an Object variable, you
can't access any members or attributes of the object other than the ones
exposed through the last interface it used as before it went -in- to the
Object variable. What a mess.
2. Using composition and delegation to simulate inheritance:
Since you can't have one class implicitly inherit from and extend another, the
next thing that comes to mind is to create an "inheriting" class that exposes
the same methods as and contains an instance of the parent class, then
forwards calls to the contained "parent" from any method that is not supposed
to override the parent behavior.
In practice, this is a seious hassle. If you use interfaces, the compiler
will tell you when a change to the parent necessitates a change to the
"inheriting" class, but with all the overhead of interfaces discussed above.
If you use late binding and no interfaces, then you don't have the hassle, but
you also don't have the compiler forcing you to update the inheriting classes
when a parent changes, and it can be a lot of effort tracking them down. As a
final blow, you can't inherit and override anything private to the "parent"
class.
Next, for some things that often do work well.
1. Using late binding for polymorphism:
Rather than using interfaces, you can simply allow code to use instances of
certain classes polymorhically by storing everything in a simple Object
variable.
This technique does have some notable down-sides, but the up-sides can often
outweigh it. The biggest down-side is that the compiler can't make sure that
only classes that follow a particular interface can be passed to procedures
that expect to use that interface. If it breaks, it will break at run-time.
The big up-side is that it doesn't require much code overhead at all.
If there's a part of your code that's really begging for a large number of
classes to be used interchangeably by some procedures, this may be a good way
to go. To mitigate the down-sides, try to make sure code that's written this
way will pass instances of every class that might be passed, and call
everything that might be called one each one early in testing. That way, if
you do break something, you'll know about it before you deploy it. If
necessary, write some automated tests as insurance, and run them before each
deployment.
2. Use inverted containership (I believe my way of doing this is a version of
the "Decorator Pattern").
In this pattern, you implement something resembling inheritance by having one
class that always acts as the interface layer, and its run-time behavior is
determined by what kind of class instance it is encapsulating at run-time. In
other words, you might "decorate" a clsQuery class by supplying it with an
instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly
accessible interface, and clsInvoiceLineQuerySpec has method signatures
clsQuery understands that provide the clsQuery instance with specific data
constants and procedures that enable it to operate in a specific context (e.g.
a SQL string).
Note that in this case, it can be somewhat practical to use an "Interface" for
the specific classes to define what they must make available to the general
interface class. The specific classes might never need to be accessed any
other way than through that interface, so there are no ambiguities or wrapped
calls to worry about.
3. Instances as "classes":
In many cases, it is sufficient to customize the behavior of an object through
initialization data alone. In this case, you can have a public function that
initializes an object with the correct data, and returns it. A form of
inheritance can be implemented in this scheme by supplying each class with a
Clone procedure, so you can clone one and extend or modify its behavior to
handle a more specific case.
For instance, let's say I have a class clsQuery that gets all its behavior
from the values of members called ParametersClause, SelectList, FromClause,
WhereClause, GroupByClause, and HavingClause. Now, let's say you provide a
public function called InvoiceLineQuery that initializes a clsQuery instance
with SelectList = "tblInvoiceLines.*" and FromClause = "tblInvoices". Now,
you have an object that can query the entire tblInvoiceLines table.
Now, implement another function called InvoiceLinesForInvoice that calls
InvoiceLineQuery to get an instance, then sets ParametersClause =
"prmInvoiceId Long" and WhereClause =
"tblInvoiceLines.InvoiceId=prmInvoiceId". This instance can be used to query
just the lines for a particular invoice.
As you can see, this can be a reasonably useful sort of real inheritance.
Note that .NET does similar things with the WindowsForms model. Each
WindowsForm object is constructed at run-time, but the code structures that do
the construction allow for a sort of inheritance by sequential addition of
items to the form's collections. I believe this is another sort of
implementation of the "Decorator Pattern". 12 6805
Somehow, I can't seem to post anything to Usenet without suddenly finding a
glaring editing mistake right after posting it. The classing Visual Basic and VBA support for polymorphism, let's face it, is a bit on the weak side, and built-in support for inheritance is non-existent.
That should read...
The Visual Basic and VBA support for class polymorphism, let's face it, is a
bit on the weak side, and built-in support for inheritance is non-existent.
Steve Jorgensen wrote: 2. Use inverted containership (I believe my way of doing this is a version of the "Decorator Pattern").
In this pattern, you implement something resembling inheritance by having one class that always acts as the interface layer, and its run-time behavior is determined by what kind of class instance it is encapsulating at run-time. In other words, you might "decorate" a clsQuery class by supplying it with an instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly accessible interface, and clsInvoiceLineQuerySpec has method signatures clsQuery understands that provide the clsQuery instance with specific data constants and procedures that enable it to operate in a specific context (e.g. a SQL string).
Note that in this case, it can be somewhat practical to use an "Interface" for the specific classes to define what they must make available to the general interface class. The specific classes might never need to be accessed any other way than through that interface, so there are no ambiguities or wrapped calls to worry about.
Actually, you don't decorate an object by passing it an instance of
another object. You decorate an object by passing it to an instance
of the decorator object. Polymorphism (via an interface) is fundamental
to the pattern so that you can sequentially decorate the initial object
with any number of additional objects. When the defined method(s) are
called on the last decorator they are called last in first out on all
the contained objects.
It might be entertaining to build a query that way, but your #3 way of
simply building a class with all the necessary methods probably makes
more sense.
On Thu, 16 Dec 2004 02:12:53 GMT, rkc <rk*@rochester.yabba.dabba.do.rr.bomb>
wrote: Steve Jorgensen wrote:
.... Actually, you don't decorate an object by passing it an instance of another object. You decorate an object by passing it to an instance of the decorator object. Polymorphism (via an interface) is fundamental to the pattern so that you can sequentially decorate the initial object with any number of additional objects. When the defined method(s) are called on the last decorator they are called last in first out on all the contained objects.
Regarding the Decorator Pattern, it sounds like I really don't get it. I'll
try to get more clear on that and also see if I can figure out what if any
existing named pattern my pattern actually resembles.
It might be entertaining to build a query that way, but your #3 way of simply building a class with all the necessary methods probably makes more sense.
I agree. Option 3 is what I normally use for query classes, and it works
really well. I have found option 2 to work well with reader/writer classes,
but the explanation of that is a bit lengthy.
On Thu, 16 Dec 2004 02:12:53 GMT, rkc <rk*@rochester.yabba.dabba.do.rr.bomb>
wrote: Steve Jorgensen wrote:
2. Use inverted containership (I believe my way of doing this is a version of the "Decorator Pattern").
In this pattern, you implement something resembling inheritance by having one class that always acts as the interface layer, and its run-time behavior is determined by what kind of class instance it is encapsulating at run-time. In other words, you might "decorate" a clsQuery class by supplying it with an instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly accessible interface, and clsInvoiceLineQuerySpec has method signatures clsQuery understands that provide the clsQuery instance with specific data constants and procedures that enable it to operate in a specific context (e.g. a SQL string).
Note that in this case, it can be somewhat practical to use an "Interface" for the specific classes to define what they must make available to the general interface class. The specific classes might never need to be accessed any other way than through that interface, so there are no ambiguities or wrapped calls to worry about.
Actually, you don't decorate an object by passing it an instance of another object. You decorate an object by passing it to an instance of the decorator object. Polymorphism (via an interface) is fundamental to the pattern so that you can sequentially decorate the initial object with any number of additional objects. When the defined method(s) are called on the last decorator they are called last in first out on all the contained objects.
OK, I get it now. From what I can tell, the pattern I'm describing most
closely resembles the "Strategy Pattern". http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
As for option 3, it seems to be most like the prototype pattern. I often use
a public function to make new "prototypes" rather than clone them from a true
prototype, but it's still pretty close. http://www.c-sharpcorner.com/Languag...rnsinCSRVS.asp
Interesting Point
"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:7g********************************@4ax.com... Somehow, I can't seem to post anything to Usenet without suddenly finding
a glaring editing mistake right after posting it.
The classing Visual Basic and VBA support for polymorphism, let's face
it, isa bit on the weak side, and built-in support for inheritance is
non-existent. That should read...
The Visual Basic and VBA support for class polymorphism, let's face it, is
a bit on the weak side, and built-in support for inheritance is
non-existent.
interesting point
"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:h3********************************@4ax.com... The classing Visual Basic and VBA support for polymorphism, let's face it,
is a bit on the weak side, and built-in support for inheritance is
non-existent. This little essay is about some patterns I've ended up using successfully
for certain kinds of inheritance and polymorphism, and some that have not
worked out so well.
Let's start with obvious things that turn out not to work well:
1. Use interface classes and "Implements" for polymorphism:
At first glance, this seems like a fine choice. After all, in languages
like Java, interface implementation is used by most programmers at least as
often as inheritance, and is better than inheritance for many things. Also,
using interfaces allows for polymorphism without breaking type safety. Alas, in
VB things are not as good as they at first appear.
As it turns out, interfaces and Implements are useful sometimes in limited circumstances, but the way they work in VB makes them often take extra
effort to maintain and makes them behave unpredictably in many circumstances. First of all, rather than simply requiring that all the interface members
be implemented and making them visible through the interface like Java would
do, VB requries you to explicitly create an implementation of each method for
each interface using a qualified name. Each of these is then a separate method that can its own different implementation (oh what a tangled web that
could be), and to make all cases act the same (like you want about 100% of the time), you must explicitly call one central method from each of the
interface implementations fo the case.
Now, if that weren't bad enough, you'd best be careful never to mix early binding and late binding code on the same classes in the wrong order
because if you set an Object variable equal to a variable of an interface type,
the object behaves as an instance of the interface it was in before you
assigned it. In other words, even though it is now housed in an Object variable,
you can't access any members or attributes of the object other than the ones exposed through the last interface it used as before it went -in- to the Object variable. What a mess.
2. Using composition and delegation to simulate inheritance:
Since you can't have one class implicitly inherit from and extend another,
the next thing that comes to mind is to create an "inheriting" class that
exposes the same methods as and contains an instance of the parent class, then forwards calls to the contained "parent" from any method that is not
supposed to override the parent behavior.
In practice, this is a seious hassle. If you use interfaces, the compiler will tell you when a change to the parent necessitates a change to the "inheriting" class, but with all the overhead of interfaces discussed
above. If you use late binding and no interfaces, then you don't have the hassle,
but you also don't have the compiler forcing you to update the inheriting
classes when a parent changes, and it can be a lot of effort tracking them down.
As a final blow, you can't inherit and override anything private to the
"parent" class.
Next, for some things that often do work well.
1. Using late binding for polymorphism:
Rather than using interfaces, you can simply allow code to use instances
of certain classes polymorhically by storing everything in a simple Object variable.
This technique does have some notable down-sides, but the up-sides can
often outweigh it. The biggest down-side is that the compiler can't make sure
that only classes that follow a particular interface can be passed to
procedures that expect to use that interface. If it breaks, it will break at
run-time. The big up-side is that it doesn't require much code overhead at all.
If there's a part of your code that's really begging for a large number of classes to be used interchangeably by some procedures, this may be a good
way to go. To mitigate the down-sides, try to make sure code that's written
this way will pass instances of every class that might be passed, and call everything that might be called one each one early in testing. That way,
if you do break something, you'll know about it before you deploy it. If necessary, write some automated tests as insurance, and run them before
each deployment.
2. Use inverted containership (I believe my way of doing this is a version
of the "Decorator Pattern").
In this pattern, you implement something resembling inheritance by having
one class that always acts as the interface layer, and its run-time behavior
is determined by what kind of class instance it is encapsulating at run-time.
In other words, you might "decorate" a clsQuery class by supplying it with an instance of clsInvoiceLineQuerySpec. clsQuery provides the publicly accessible interface, and clsInvoiceLineQuerySpec has method signatures clsQuery understands that provide the clsQuery instance with specific data constants and procedures that enable it to operate in a specific context
(e.g. a SQL string).
Note that in this case, it can be somewhat practical to use an "Interface"
for the specific classes to define what they must make available to the
general interface class. The specific classes might never need to be accessed any other way than through that interface, so there are no ambiguities or
wrapped calls to worry about.
3. Instances as "classes":
In many cases, it is sufficient to customize the behavior of an object
through initialization data alone. In this case, you can have a public function
that initializes an object with the correct data, and returns it. A form of inheritance can be implemented in this scheme by supplying each class with
a Clone procedure, so you can clone one and extend or modify its behavior to handle a more specific case.
For instance, let's say I have a class clsQuery that gets all its behavior from the values of members called ParametersClause, SelectList,
FromClause, WhereClause, GroupByClause, and HavingClause. Now, let's say you provide
a public function called InvoiceLineQuery that initializes a clsQuery
instance with SelectList = "tblInvoiceLines.*" and FromClause = "tblInvoices".
Now, you have an object that can query the entire tblInvoiceLines table.
Now, implement another function called InvoiceLinesForInvoice that calls InvoiceLineQuery to get an instance, then sets ParametersClause = "prmInvoiceId Long" and WhereClause = "tblInvoiceLines.InvoiceId=prmInvoiceId". This instance can be used to
query just the lines for a particular invoice.
As you can see, this can be a reasonably useful sort of real inheritance. Note that .NET does similar things with the WindowsForms model. Each WindowsForm object is constructed at run-time, but the code structures
that do the construction allow for a sort of inheritance by sequential addition of items to the form's collections. I believe this is another sort of implementation of the "Decorator Pattern".
Steve Jorgensen wrote: On Thu, 16 Dec 2004 02:12:53 GMT, rkc
<rk*@rochester.yabba.dabba.do.rr.bomb> wrote:
OK, I get it now. From what I can tell, the pattern I'm describing
most closely resembles the "Strategy Pattern".
http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example?
Thanks,
JAF
I found this thread interesting and thought I would share my humble 2
cents worth in exchange for a general question about .Net that I have
which is slightly related to this topic for which I have not found an
answer.
As for simulating OOP stuff with vb6 and vba, the best I was able to
come up with that was somewhat reliable was overloading - by creating a
class object and send the same named object any variety of arguments
where the class contains a variety of methods for various args - kind of
like reiventing the wheel in an OOP language where the same thing is
done for you under the hood. I do this overloading thing in Access
quite frequently because this way I can call a variety of methods with
the same name (overloading) in a loop. And a plug for vb.net, I use
Interfaces and delegate frequently (well, maybe not delegates so much -
function pointers) and I have not had any issues in vb.net. For OOP
languages, vb (vb.net) still maintains the lead in ease of use and
development speed and is almost as sophisticated as C# and Java. I
noticed that C# and Java don't have as much intellisense as vb.net. I
have had to start using C# on more and more projects, and when I can't
figure out a syntax, I write the equivalent code in a test vb.net app
and look at the intellisense. In Java, well, I write Java only when I
really have to (for Lotus Notes). So here is my general question about
OOP and dotnet.
In vb6 I have developed several ActiveX.exe apps so that I can use
CreateObject and GetObject, the same as Access, Excel, Word. I have not
yet found a way to create the equivalent of an ActiveX.exe app in dotnet
and no one is talking about such a thing. So would anyone know if there
is such a thing in dotnet that is equivalent to the Com ActiveX.exe? If
not, is there a way for dotnet apps to interact with each other like Com
ActiveX.exe apps (Access, Excel, Word, etc)?
Rich
*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it! ji********@compumarc.com wrote: http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example?
Here's a small and basically useless example of a Strategy pattern.
I think it does show pretty clearly how it works though.
<TestStrategy type="client code">
Public Sub TestStrategy()
Dim c As clsContext
Dim qryStrat As IQueryStrategy
Set c = New clsContext
Set qryStrat = New clsDLookupStrategy
qryStrat.build "Employees", "LastName", "EmployeeID = 1"
c.setStrategy qryStrat
MsgBox c.result
Set qryStrat = Nothing
Set c = Nothing
End Sub
</TestStrategy>
<IQueryStrategy type="Interface">
Private domain As String
Private expression As String
Private criteria As String
Public Sub build(sDomain As String, sExpression As String, sCriteria As
String)
'method body
End Sub
Public Function execute() As String
'method body
End Function
</IQueryStrategy>
<clsDLookupStrategy>
Implements IQueryStrategy
Private domain As String
Private expression As String
Private criteria As String
Private Sub IQueryStrategy_build(sDomain As String, sExpression As
String, sCriteria As String)
domain = sDomain
expression = sExpression
criteria = sCriteria
End Sub
Private Function IQueryStrategy_execute() As String
Dim s As String
s = DLookup(expression, domain, criteria)
IQueryStrategy_execute = "" & s
End Function
</clsDLookupStrategy>
<clsSqlStrategy>
Implements IQueryStrategy
Private domain As String
Private expression As String
Private criteria As String
Private Sub IQueryStrategy_build(sDomain As String, sExpression As
String, sCriteria As String)
domain = sDomain
expression = sExpression
criteria = sCriteria
End Sub
Private Function IQueryStrategy_execute() As String
Dim rs As DAO.Recordset
Dim s As String
Dim sql As String
sql = "SELECT " & expression & _
" FROM " & domain & _
" WHERE " & criteria
Set rs = CurrentDb.OpenRecordset(sql)
With rs
If Not .EOF Then
s = .Fields(0)
End If
.Close
End With
Set rs = Nothing
IQueryStrategy_execute = "" & s
End Function
</clsSqlStrategy>
<clsContext>
Private qry As IQueryStrategy
Public Sub setStrategy(stgy As IQueryStrategy)
Set qry = stgy
End Sub
Public Function result() As String
result = qry.execute
End Function
</clsContext>
Hi Jim,
.... http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example? Thanks, JAF
I finally got time to make up a little example for ya in addition to the one
RKC posted. This is not air code - it's tested and it works, though it is
obviously missing some error handling it would need for use in a production
app.
=== Module: basTestLogWriter
Option Compare Database
Option Explicit
Public Sub TestTxtFileLogWriter()
Dim objWriterStrategy As New clsLogWriterTxtFileStrategy
objWriterStrategy.FilePath = CurrentProject.Path & "\" & _
"LogWriterTest.txt"
WriteLogData objWriterStrategy
End Sub
Public Sub TestTableLogWriter()
Dim objWriterStrategy As New clsLogWriterTableStategy
With objWriterStrategy
.DbFilePath = CurrentProject.Path & "\" & _
"Log Writer Test Output.mdb"
.TableName = "tblLogEntry"
.FieldName = "LogEntryText"
End With
WriteLogData objWriterStrategy
End Sub
Private Sub WriteLogData(WriterStrategy As ILogWriterStrategy)
Dim objWriter As New clsLogWriter
objWriter.Setup WriterStrategy
objWriter.OpenLog
With objWriter
.WriteMessage "Test message 1"
.WriteMessage "Test message 2"
End With
objWriter.CloseLog
End Sub
=== Module: clsLogWriter
Option Compare Database
Option Explicit
Private mobjStrategy As ILogWriterStrategy
Public Sub Setup(Strategy As ILogWriterStrategy)
Set mobjStrategy = Strategy
End Sub
Public Property Get Strategy() As ILogWriterStrategy
Set Strategy = mobjStrategy
End Property
Public Sub OpenLog()
Strategy.OpenLog
End Sub
Public Sub CloseLog()
Strategy.CloseLog
End Sub
Public Sub WriteMessage(Message As String)
Dim strFormattedMsg As String
strFormattedMsg = FormatMessage(Message)
Strategy.WriteFormattedMsg strFormattedMsg
End Sub
Private Function FormatMessage(Message As String) As String
Const cstrTimestampFormat = "yyyy-mmm-dd hh:nn a/p"
Dim strTimestamp As String
strTimestamp = Format(Now, cstrTimestampFormat)
FormatMessage = BulletChar & " " & _
strTimestamp & ": " & _
Message
End Function
Private Function BulletChar() As String
BulletChar = Chr$(149)
End Function
=== Module: ILogWriterStrategy
Option Compare Database
Option Explicit
Public Sub OpenLog()
End Sub
Public Sub CloseLog()
End Sub
Public Sub WriteFormattedMsg(Message As String)
End Sub
=== Module: clsLogWriterTxtFileStrategy
Option Compare Database
Option Explicit
Implements ILogWriterStrategy
Public FilePath As String
Private mintFileNum As Integer
Public Sub ILogWriterStrategy_OpenLog()
mintFileNum = FreeFile
Open FilePath For Output As mintFileNum
End Sub
Public Sub ILogWriterStrategy_CloseLog()
Close mintFileNum
End Sub
Public Sub ILogWriterStrategy_WriteFormattedMsg( _
Message As String _
)
Print #mintFileNum, Message
End Sub
=== Module: clsLogWriterTableStategy
Option Compare Database
Option Explicit
Implements ILogWriterStrategy
Public DbFilePath As String
Public TableName As String
Public FieldName As String
Private mdbsLogDb As DAO.Database
Private mrstLogTable As DAO.Recordset
Public Sub ILogWriterStrategy_OpenLog()
Set mdbsLogDb = Workspaces(0).OpenDatabase(DbFilePath)
Set mrstLogTable = mdbsLogDb.OpenRecordset(TableName, _
dbOpenDynaset, _
dbAppendOnly)
End Sub
Public Sub ILogWriterStrategy_CloseLog()
mrstLogTable.Close
mdbsLogDb.Close
End Sub
Public Sub ILogWriterStrategy_WriteFormattedMsg( _
Message As String _
)
mrstLogTable.AddNew
mrstLogTable(FieldName) = Message
mrstLogTable.Update
End Sub
On 16 Dec 2004 10:32:46 -0800, ji********@compumarc.com wrote: Steve Jorgensen wrote: On Thu, 16 Dec 2004 02:12:53 GMT, rkc <rk*@rochester.yabba.dabba.do.rr.bomb> wrote:
OK, I get it now. From what I can tell, the pattern I'm describing most closely resembles the "Strategy Pattern".
http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example? Thanks, JAF
Steve Jorgensen wrote: Hi Jim,
...
http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example? Thanks, JAF
I finally got time to make up a little example for ya in addition to the one RKC posted. This is not air code - it's tested and it works, though it is obviously missing some error handling it would need for use in a production app.
Usefull example. It's pretty clear how it could be easily extended to
write to an XML file, another database or even an spreadsheet.
You also got the handling of the data in the context class
(clsLogWriter)where it belongs. I got that wrong. Not sure why you
expose Private mobjStrategy with a property get though.
The file setup code in the test module is ugly, but then I realized
in real life you would probably handle that in the strategy classes
via config data stored outside the application code.
On Mon, 20 Dec 2004 01:06:06 GMT, rkc <rk*@rochester.yabba.dabba.do.rr.bomb>
wrote: Steve Jorgensen wrote: Hi Jim,
...
http://www.exciton.cs.rice.edu/JavaR...egyPattern.htm
I really like this idea. Can you post code for a small example? Thanks, JAF
I finally got time to make up a little example for ya in addition to the one RKC posted. This is not air code - it's tested and it works, though it is obviously missing some error handling it would need for use in a production app.
Usefull example. It's pretty clear how it could be easily extended to write to an XML file, another database or even an spreadsheet. You also got the handling of the data in the context class (clsLogWriter)where it belongs. I got that wrong. Not sure why you expose Private mobjStrategy with a property get though.
That was a case of "I needed it last time, so..." Frankly, I don't remember
why I need a public Strategy member, so I probably should have left it out
until the need arises again.
The file setup code in the test module is ugly, but then I realized in real life you would probably handle that in the strategy classes via config data stored outside the application code.
Pretty much, yeah. This was the minumum code I thought I could write that
would fully demonstrate the template pattern, and why it would be useful. This discussion thread is closed Replies have been disabled for this discussion. Similar topics
37 posts
views
Thread by Mike Meng |
last post: by
|
reply
views
Thread by Faraz |
last post: by
|
10 posts
views
Thread by Lino Barreca |
last post: by
|
13 posts
views
Thread by Fao |
last post: by
|
60 posts
views
Thread by Shawnk |
last post: by
|
18 posts
views
Thread by Seigfried |
last post: by
|
11 posts
views
Thread by chsalvia |
last post: by
|
8 posts
views
Thread by weird0 |
last post: by
| | | | | | | | | | | |