Sharing an instance of an object across classes

B

Beth

Hello.

I'm trying to find another way to share an instance of an object with other
classes.

I started by passing the instance to the other class's constructor, like this:

Friend Class clsData
Private m_objSQLClient As clsSQLClient
Private m_objUsers As clsUsers
Private m_sConnect As String

Friend Sub connect(ByVal bDebuggerAttached As Boolean)
Dim sServer As String
Dim sDB As String

If bDebuggerAttached Then
sServer = "test"
Else
sServer = "prod"
End If
sDB = "appdb"

m_sConnect = "Data Source=" & sServer & ";Database=" & sDB & ";Integrated
Security=true"
m_sConnect = m_sConnect & ";Application Name = " &
My.Application.Info.AssemblyName

m_objSQLClient = New clsSQLClient
m_objSQLClient.connect(m_sConnect)

m_objUsers = New clsUsers(m_objSQLClient)
End Sub
End Class

Friend Class clsUsers
Private m_objSQLClient As clsSQLClient
Private m_dtUser As DataTable

Friend Sub New(ByVal objSQLClient As clsSQLClient)
m_objSQLClient = objSQLClient
End Sub

Friend Function markEntry() As String
Try
m_dtUser = m_objSQLClient.tableForEdit("users")

This works, but I don't like it. I want clsUsers to refer directly to the
instance variable in clsData instead of passing a parameter.

Then I saw an example using inheritance that I liked, so I added:

Protected Friend Function sqlClient() As clsSQLClient
Return m_objSQLClient
End Function

To clsData and I deleted the constructor in clsUsers and changed the code to:

Friend Class clsUsers
Inherits clsData
Private m_dtUser As DataTable

Friend Function markEntry() As String
Try
m_dtUser = MyBase.sqlClient.tableForEdit("users")

but it doesn't work- it raises an exception when clsUsers.markEntry
references mybase.sqlClient.

Is there another way I can do this, or do I need to stick with passing the
object instance as a parameter?

Thanks for any help,

-Beth
 
T

Tom Shelton

Hello.

I'm trying to find another way to share an instance of an object with other
classes.

I started by passing the instance to the other class's constructor, like this:

Friend Class clsData
Private m_objSQLClient As clsSQLClient
Private m_objUsers As clsUsers
Private m_sConnect As String

Friend Sub connect(ByVal bDebuggerAttached As Boolean)
Dim sServer As String
Dim sDB As String

If bDebuggerAttached Then
sServer = "test"
Else
sServer = "prod"
End If
sDB = "appdb"

m_sConnect = "Data Source=" & sServer & ";Database=" & sDB & ";Integrated
Security=true"
m_sConnect = m_sConnect & ";Application Name = " &
My.Application.Info.AssemblyName

m_objSQLClient = New clsSQLClient
m_objSQLClient.connect(m_sConnect)

m_objUsers = New clsUsers(m_objSQLClient)
End Sub
End Class

Friend Class clsUsers
Private m_objSQLClient As clsSQLClient
Private m_dtUser As DataTable

Friend Sub New(ByVal objSQLClient As clsSQLClient)
m_objSQLClient = objSQLClient
End Sub

Friend Function markEntry() As String
Try
m_dtUser = m_objSQLClient.tableForEdit("users")

This works, but I don't like it. I want clsUsers to refer directly to the
instance variable in clsData instead of passing a parameter.

Then I saw an example using inheritance that I liked, so I added:

Protected Friend Function sqlClient() As clsSQLClient
Return m_objSQLClient
End Function

To clsData and I deleted the constructor in clsUsers and changed the code to:

Friend Class clsUsers
Inherits clsData
Private m_dtUser As DataTable

Friend Function markEntry() As String
Try
m_dtUser = MyBase.sqlClient.tableForEdit("users")

but it doesn't work- it raises an exception when clsUsers.markEntry
references mybase.sqlClient.

Is there another way I can do this, or do I need to stick with passing the
object instance as a parameter?

Thanks for any help,

-Beth

First of all, it is usually a bad idea to allow other classes, included sub
classes direct access to instance variables. It should always be through
properties. In fact, I try to never access field data even inside my own
class without going through properties :) The main reason is that properties
provide a layer of abstraction, that allows the implmentation change without
having affecting client code... For instance, what if a field needs to
become a calculated value? If you went through the property, all is well, but
if you allowed client code to directly access the field then you are in
trouble. Believe me, I have learned this lesson the hard way :)

That said... Let's see if we can't come up with a good answer, to your
problem :) Based off of what I'm seeing here, I don't see the problem with
your first example? Why do you feel it is better not to pass the parameter to
the constructor - though, I would probably do it more like this:


Class clsData
Private _sqlClient As clsSqlClient
private _users As clsUsers

Public Sub New (....)
SqlClient = new clsSqlClient(....)

Users = New clsUsers (SqlClient)
End Sub

Private Property Users As clsUsers
Get
Return _users
End Get
Set (ByVal Value As clsUsers)
_users = Value
End Set
End Property
Private Property SqlClient As clsSqlClient
Get
Return _sqlClient
End Get
Set (ByVal Value As SqlClient)
_sqlClient = Value
End Set
End Property

End Class


Anyway, that's my oppinion, others may differ. And it maybe another approach
my be better if you application has a different achitecture. Like, do all
isntances of all classes use the same SqlClient instance, etc.
 
B

Beth

Hi, Tom.
Thanks for your response.

Yes, multiple classes share a single instance of clsSQLClient connected to
the server. Right now, I'm passing it as a parameter to each of the class's
constructors.

ClsData is intended to wrap all of the data access functions of the
application.
ClsSQLClient Imports System.Data.SqlClient, and is the only class to do so.
ClsUsers has a 'has-a' relationship with clsData: the data object includes a
representation of the users table in the database.

I'm trying to figure out how to share an instance of a variable without
using inheritance. For a 'has-a' relationship (composition,) I've read
you're supposed to use interfaces instead of inheritance, but interfaces
don't contain implementation, so you can't share instances of objects at
runtime.

Maybe what I'm doing is what I'm 'supposed' to be doing, but I don't like my
class diagram having all these other classes point to my clsSQLClient.
I only want clsData to point to it, and all the other classes to point to
clsData.

When I tried to use inheritance, I got a nicer diagram, but broke the app.

Also, I'm not sure what you're referring to when you say it's:
a bad idea to allow other classes, included sub classes direct access to
instance variables

I didn't think I was allowing direct access to the private instance
variables outside of the classes. I agree, it's a bad idea, but I'm not
seeing where I'm doing it.

Thanks again for your response. I'm sticking with the parameters for now.

-Beth
 
S

sloan

I think that whole bit of code is ... .. hurting.....

You're tied your clsUsers to always coming from the database.
Based on the notation (hungarian), this looks like leftover VB6 code, and no
one at your workplace has taken a VB.NET course yet.

Take a look here:

http://sholliday.spaces.live.com/Blog/cns!A68482B9628A842A!140.entry

This is a layered application.

The business objects and collections are seperate from the code that creates
them.
The code that creates them can use database related calls, OR (better) the
business objects and collections can be created totally independant of a
database.
(One reason? UnitTesting)

Your connection strings should be kept in a config file. You've got
hardcoding all over the place.


I'm not trying to be mean...but youch....... I have no idea what that code
is doing. I might have in 1999.



................
 
T

Tom Shelton

Hi, Tom.
Thanks for your response.

Yes, multiple classes share a single instance of clsSQLClient connected to
the server. Right now, I'm passing it as a parameter to each of the class's
constructors.

ClsData is intended to wrap all of the data access functions of the
application.
ClsSQLClient Imports System.Data.SqlClient, and is the only class to do so.
ClsUsers has a 'has-a' relationship with clsData: the data object includes a
representation of the users table in the database.

Hmmm... Sounds to me like you need something along the lines of a
singleton...

Class clsData
Private Shared _instance As New clsData
....

' your public instance methods here

Public Shared ReadOnly Property Instance As clsData
Get
return _instance
End Get
End Property
End Class

Class User
...

Public Sub SomeSub()
clsData.Instance.DoCoolStuff()
End Sub
End Class


Also, I'm not sure what you're referring to when you say it's:
a bad idea to allow other classes, included sub classes direct access to
instance variables

I didn't think I was allowing direct access to the private instance
variables outside of the classes. I agree, it's a bad idea, but I'm not
seeing where I'm doing it.

Your probably not :) I didn't look that close, but I was just commenting on
your remark about allowing clsUsers direct access to the instance variable.
 
T

Tom Shelton

I think that whole bit of code is ... .. hurting.....

You're tied your clsUsers to always coming from the database.
Based on the notation (hungarian), this looks like leftover VB6 code, and no
one at your workplace has taken a VB.NET course yet.

Take a look here:

http://sholliday.spaces.live.com/Blog/cns!A68482B9628A842A!140.entry

This is a layered application.

The business objects and collections are seperate from the code that creates
them.
The code that creates them can use database related calls, OR (better) the
business objects and collections can be created totally independant of a
database.
(One reason? UnitTesting)

Your connection strings should be kept in a config file. You've got
hardcoding all over the place.


I'm not trying to be mean...but youch....... I have no idea what that code
is doing. I might have in 1999.



...............

Yep... I have to agree.
 
B

Beth

Thanks, Tom.

It looks recursive, but I see where the new instance of the class is created
during the declaration instead of outside the class, enforcing the single
shared instance, as long as no caller decides to instantiate the class.

I got the instance reference to work without passing an instance of the
class as a parameter to other class's constructors, and that was what I
wanted.

I think what I was looking for before was some kind of 'functional'
inheritance, which doesn't seem to exist.

I was thinking when you instantiate a derived class, it 'latched on' to the
base class instance in memory, so you could call the base class's functions
at runtime and get the same results as if you'd called the base class's
functions directly, but it doesn't work that way. The derived class has its
own instance of myBase separate from any other instance, which makes sense,
because you're not guaranteed to have any instance of the base class in
memory or you could have several instances, and then which one would the
derived class 'latch on' to?

Thanks again for your response. I'd seen the 'shared' keyword before, but
not used on a new instance of itself.

I guess that's what they mean by 'singleton.'

-Beth
 
T

Tom Shelton

Thanks, Tom.

It looks recursive, but I see where the new instance of the class is created
during the declaration instead of outside the class, enforcing the single
shared instance, as long as no caller decides to instantiate the class.

I got the instance reference to work without passing an instance of the
class as a parameter to other class's constructors, and that was what I
wanted.

I think what I was looking for before was some kind of 'functional'
inheritance, which doesn't seem to exist.

I was thinking when you instantiate a derived class, it 'latched on' to the
base class instance in memory, so you could call the base class's functions
at runtime and get the same results as if you'd called the base class's
functions directly, but it doesn't work that way. The derived class has its
own instance of myBase separate from any other instance, which makes sense,
because you're not guaranteed to have any instance of the base class in
memory or you could have several instances, and then which one would the
derived class 'latch on' to?

Thanks again for your response. I'd seen the 'shared' keyword before, but
not used on a new instance of itself.

I guess that's what they mean by 'singleton.'

-Beth

Actually, there is a mistake in that implementation... clsData should have a
private constructor. In other words, it should prevent any other classes from
instantiating it :)

Here is the correction...

Class clsData
Private Shared _instance As New clsData
....
Private Sub New ()
' this should probably read your connection
' information from the connectionstrings section
' of your config file
End Sub

' your public instance methods here

Public Shared ReadOnly Property Instance As clsData
Get
return _instance
End Get
End Property
End Class

Now, there is only on instance of this class. I am not saying this is the
correct architecture. The more I've read, it sounds like you are trying to
develop a n-teir type application. You might want to do some reading on that
topic.
 
B

Beth

Thanks again, Tom.
I like that better.

I've read about n-tier development, but that's not really what I'm doing.
Everything is in one assembly for one project with one database. It's not a
large-scale thing, just departmental. It's not dependent on any modules
running on other servers, in other words.
 
T

Tom Shelton

but you can't listen for events from a singleton...

Sure you can.

I'm still not convined that this is the right path. I think really, more
information is needed on what your trying to achieve.

If I understand, now that I've read more - it sounds like your trying to
create a data abstraction layer. There are many ways to accomplish this, so
you might want to do a little more reading on n-tier achitectures. There are
in fact whole applications that will generate this kind of stuff for you :)

But, for simple stuff, I tend to do stuff like this

Friend MustInherit Class DataAccess
Private _connectionString As String

Public Sub New(ByVal connectionString As String)
_connectionString = connectionString
End Sub

' generic data access stuff

Public Function GetList(Of T) (ByVal procedure) As List(Of T)
Dim l As New List(Of T)
' I use attributes and reflection to generate the objects here
' from the resulting recordset. basically, i map the properties
' of type T to specific fields in the record set.
Return l
End Function
End Class

Friend Class UserDataAccess
Inherits DataAccess

Public Sub New (ByVal connectionString As String)
MyBase.New(connectionString)
End Sub

Public Function GetUsers() As List(Of User)
Return GetList(Of User)("getallusers")
End Function

Public Class

Public Class UserBuisnessLogic
Private _dataAccess As UserDataAccess

Public Sub New (string connectionString)
_dataAccess = new UserDataAccess
End Sub

Public Function GetUsers() As List(Of User)
return _dataAccess.GetUsers()
End Function
End Class

This of course Really, Really, basic. I have a framework that I've been
evolving overtime :) And to be real honest, it's all in C# - but many of the
concepts apply to VB. But, you might want to take a look at some resources on
this topic.
 
T

Tom Shelton

Thanks again, Tom.
I like that better.

I've read about n-tier development, but that's not really what I'm doing.
Everything is in one assembly for one project with one database. It's not a
large-scale thing, just departmental. It's not dependent on any modules
running on other servers, in other words.

N-Tier is more about a separation of layers then it is about multiple servers,
etc. N-tier is about layering of you application into multiple independent
layers. I often have one dll that contains all three layers - the point is
that I can easily separate them out, split them up or replace layers with
different pieces should the need arise.
 
B

Beth

Thanks, sloan.
I think.

Yes, I've been developing over 10 years now. I started with VB3, believe it
or not.
And yes, I have taken a couple of .NET courses. Didn't get through to me, I
guess.

Actually, I used to think I could support anybody else's VB code, until I
saw some written by a guy experienced in COBOL. Then I saw some code written
by engineers. Then I saw some code written by a FoxPro developer.

I usually rewrite the old stuff instead of trying to figure out what they
were doing.

So I gather...
You don't like my naming convention. Personally, I like being able to tell
the data type from the variable name.

You were thinking I was working on components that didn't access the
database directly? That I was implementing some middle-tier components? I'm
doing the whole thing, soup to nuts (actually, I've done the whole thing and
I'm revisiting it.)
I could have introduced additional layers of abstraction, but for this
project, it didn't make sense. It would be introducing abstraction for
abstraction's sake, not reuse.

You want to see connection strings in a config file instead of code. I'm
not a huge fan of config files, but I have seen them promoted. It's an
internal application using integrated security, so all I'm concerned about is
keeping people from accessing the wrong back end. I need to keep people in
prod from connecting to test, even though prod started out in the test
environment and they're structurally the same. I'm even exposing the
connection in Help/About so we're all clear on where we're connecting at
runtime.

You want to see the use of lists instead of collections. I think I can
accommodate you, there.

It's certainly not my intention to write code which pains you young
whipper-snappers, so if there's more I was supposed to pick up on, feel free
to share.

I need to take my nap now.

-Beth
 
S

sloan

You can write layers into one assembly....layers are a logical seperation.

I think its easier to put layers in different assembies (to avoid crossing
incorrect boundaries)......but you can do layers in one assembly.

I think of Tiers as different boundaries.

But you should be doing Layered development.
 
S

sloan

//which pains you young
whipper-snappers,//

Huh?
I've been developing code for 10 years also (as in being paid ... for a
living).
I started with VB4, 16Bit for Win3.1.

So I don't think age has anything to do with it.


If you count the space invader knock-off game I wrote in the 6th grade on a
TRS80 using ascii characters, then I've been writing code for 24 years on
and off.
Wait, I took a Apple 2e course during my 5th grade summer. Make that 25
years.
 
C

Cor Ligthert[MVP]

Beth,

It sounds for me a bad idea to use VB6 style code where OOP can be used.

But as you want that, simple use modules instead of classes.

jmo

Cor
 
C

Cor Ligthert[MVP]

Sloan,

Sorry, I did not completely read your reply before I wrote mine.

I could have written, I agree with you Sloan.

Cor
 
C

Cor Ligthert[MVP]

Tom,

I am glad you do.

I was a little bit disapointed that you were helping with this, and because
it is in a newsgroup than certainly sombody will use this in future.

Something like the by my so hated phrase "It is best
practise.................. whatever"

Cor

:-
 
M

Michel Posseth [MCP]

Hello Beth,

There is nothing wrong with passing an initialized class as a parameter to
another class even if you pass it as byvalue ( wich i would recomend )
object instances will only transfer the memory pointer , so no new
instances are created , you still hold one instance of your class .

You can easiliy proove and confirm this yourself changes in the passed class
will be reflected in the original class , so in terms of memory footprint
and perfomance this is even a bether aproach as using inheritance as this
would create a bigger footprint in the resulting code output ,


about your coding style ,,,, it would be a good idea for you to read this
book
http://astore.amazon.com/vbdotnetcoder-20/detail/0735621721/175-0134366-2373937

Although i must say i have seen worse coding styles from people honestly
believing that they comply to MSF
i am just mentioning above link because of the comments in this thread wich
are partially valid after reading and conforming to the styles in above book
you can slap 90% of the coders around for not complying to the official MSF
, Practical guidelines and best practices rules .

But ,,,, honestly said it wil sure make you a bether and more productive
programmer if you comply to the basic rules of naming conventions just for
the simple fact that a lot of tools ( devpartner profiler to just call one )
comply to these rules so in my code i just simply declare a private field
and with just a short keyborard shortcut i can convert it to a correctly
named property


Regards

Michel Posseth [MCP]
 
B

Beth

re: you should be doing Layered development

OK, I thought I was, but maybe not.

I have the presentation layer separated from the data access classes, which
are independent of the business content tables on the database.

I don't have any source code (classes) containing business content, like
customerID, name, and phone. That's all business content I don't determine.
I don't hard code that stuff because it's outside of my control and too
volatile.

My classes are dependent on tables in the database I create for my
application's use which are stored in the same database alongside the
business content tables. The content of the tables the source code is
dependent on describe how the application should display, validate, manage,
and/or exercise data in the business content tables.

I was thinking I 'should' be able to compile my data access classes into a
separate .dll so I could reuse it for a web front-end. All the data access
requirements are the same from the presentation layer's point of view.

I don't see a lot of other developers taking this approach, and I see a lot
of class examples modeling business content, so I don't really expect many
people to understand what I'm trying to do, which is one reason why it's
harder for me to get help.

Thanks for trying, anyways.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top