Solved

Global Class

Posted on 2004-04-14
48
2,789 Views
Last Modified: 2008-10-09
Hello everyone,

I would like to know the best, most efficient approach to this problem.  I have an application in which a user must login.  During login, the application checks a user database table for existence and rights.  I am going to create a class called User into which I will load all information for that user from the database.  I will need this information accessible throughout my MDI application.  Other than having to pass the class into each form or creating a new instance of the class in each form, what would be the best approach to making this class basically global??????????

Thanks,
Kendal
0
Comment
Question by:gvector1
  • 19
  • 13
  • 11
  • +4
48 Comments
 
LVL 22

Expert Comment

by:_TAD_
ID: 10825575


You could create a static class and just reference it as you need it.

public static class MyUser
{
   // all variables, functions, etc need to be static as well
}


MyUser.Name... etc. etc.
0
 
LVL 3

Expert Comment

by:int_20h
ID: 10825689
create a singleton!

public class User
{
     private User instance = null;
     static readonly object padlock = new object();

     private User()
     {}
     public static User getInstance()
     {
        if (instance==null)
        {
            lock (padlock)
            {
                if (instance==null)
                    instance = new User();
            }
        }
        return instance;  
     }
}

to get this class anywhere in your code:
User myUser = User.getInstance();
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10825737


In all honesty though, I would not reccomend this method.

A true Object Oriented would mean that Class G would never reference Class C directly, but instead would walk up the the chain to the parent class to relay information.


That is, I would decide what classes/objects I need in order to function.  I would then build the objects and build interfaces to those objects.

I would then create a Parent AppInstance object that interfaces all of the objects needed to run my application.

Then, each child object to the parent object could pick and choose which interfaces are needed in order to execute each of those child objects.  Thus through inheritance you can have all of that information at your disposal.
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10825768


You can create a singleton as int_20h suggested.  The only downside is that you have to make sure that the instance never goes out of scope, otherwise the GC will collect your object and you'll be stuck.  To avoid that you could create a static singleton, but then that's the same as just a regular static class.
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10825799


In answer to your question:
>best approach to making this class basically global???

the "best" approach is to go pure object oriented and create interfaces and use inheritance.

That, of course depends on how large the project is and how much work and design effort do you want to do.    If this is small project, sloppy coding (singltons and static classes) will be more than sufficient.  If this is a large project you will probably want somethign a bit more extensible and robust.
0
 

Author Comment

by:gvector1
ID: 10825871
This will be a large project one done and over.  

As you said in your post
>>I would then create a Parent AppInstance object that interfaces all of the objects >>needed to run my application.

>>Then, each child object to the parent object could pick and choose which interfaces >>are needed in order to execute each of those child objects.  Thus through >>inheritance you can have all of that information at your disposal.

Correct me if I am wrong.  This is my thinking of what you posted.
I take it that the object will be my User Class.  I create an instance of this class in my parent form.  I then access that instance of the class through my parent form?????  If so how??????  If the object is my user class, I guess I would ask how would you suggest I interface it.  My big aim is for efficiency in my code.

Thanks again,
Kendal
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 10825876
heh nice use of the double check pattern int20h ... very few people bother :)
0
 
LVL 3

Expert Comment

by:int_20h
ID: 10826010
Thanks gregoryyoung....  I actually found an article in MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/singletondespatt.asp

_TAD_, singletons are very useful in OO since the problem of sharing the same instance accross your app.  Regarding the GC, Singletons live until the app exits!

Reading the article .Net uses a very simple and optimize way to creating singletons:
// .NET Singleton
sealed class Singleton
{
    private Singleton() {}
    public static readonly Singleton Instance = new Singleton();
}
0
 
LVL 2

Expert Comment

by:coltrane2003
ID: 10826106
Hi,

Here's another potential approach to your solution. It's a class along with a static method inside the global class. This method uses an Xml serializer to instantiate a class instance. In this case it is used to create weblog instances, but perhaps this could be retooled for maintaining user info in your case?

The example is from Wrox press Beginning Visual C# chapter 23. You could download the code for the example at the link below.

http://www.wrox.com/books/0764543822.shtml
0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 10826114
To int_20h and gregoryyoung: The double check pattern causes troubles in most languages (C++, Java, ...)  cause the compiler optimizes the code and skips the inner null-check.
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 10826364
that it does ptmcomp. If I remember there is a way to force it to do it though.
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10826675


gvector1>

In response to your queries:
>access that instance of the class through my parent form?????  If so how??????  

I'll start with a preface that the design aspect is going to be the most critical, and the most difficult to understand.  Once you build a few apps/class with this concept it becomes as easy as breathing.... but that's later, for now it will seem like breathing underwater.


Step 1:  Follow the OO design rules fanatically, anything short will be a perversion of your project and make it difficult to extend your project in the future.

Here are the rules:

1.      The public interface of a class should only contain the operations
defined on the class. That is the data definitions should not be a part of
the public interface.

2.      Only the operations that form the interface for a class, that is,
the ones needed by the users of the class, should be the public members of
the class.

3.      An instance of a class should not send messages directly to
components of another class. That is, if there is a class C defined inside
class B, then objects of a class A should not directly perform operations on
objects of class C (though many languages will permit it).

4.      Each operation defined on a class should be such that it either
modifies or accesses some data defined in the class.

5.      A class should be dependent on as few classes as possible.

6.      The interaction between two classes should be explicit. That is,
global objects should be avoided, and any objects needed by an object should
be explicitly passed as a parameter or accessed through other explicitly
defined means.

7.      Each subclass should be developed as a specialization of the
superclass with the public interface of the superclass becoming part of the
public interface of the subclass.

8.      The inheritance hierarchy should model some hierarchy that naturally
exists, and the class definition of each level should represent some
concept. The top of the hierarchy should be an abstract class.

9.      Inside a class, case analysis on object type should be avoided. If
this is needed, then it should be done by sending messages.
      
10.      The number of arguments and the size of methods should be kept
small.

Reference: T.Korson and J.D. Gregory, Understanding object-oriented: A
unifying paradigm;

0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10827041


step 2:  Think BIG, build SMALL... Design from the top down, build from the bottom up.  That is, develop a concept (think solution), and for each facet create a new project (each solution can have many, many projects).  personally I tend towards putting all of my GUI into one or two projects and then each of my support libraries go into logical projects.  For a small to medium project, my solution will have at least 2 projects, and probably upwards of 4 or 5 projects.  If were to build an enterprise suite like MS Office (word, excel, visio, powerpoint, etc).  I'd probaly have 1 solution and perhaps 50 projects (that's just a guess).



Step 3:  Design Time

For each and every object, there is stuff going in, stuff comming out, and something happens to the stuff before we get it back.  The Class handles the "doing" part, the interface handles the in and out.


So here is a cs file


Using System;
Using System.Data;
Using MoreStuff;

public namespace myProgram
{

     public Interface IUserSecurity
     {
         string Password { get; set; }
         // contains signatures of sensitive properties like ssn, password, bank account number
     }

     public Interface IUser
     {
         string FirstName{  get; set;  }
         //contains signatures of a list of properties like fist name, last name, address zip
     }

    protected class User: IUser, IUserSecurity
    {
          public User()
          {
          }
           
          public FirstName
          {
              get{ return <some data>;}
              set{ <vaidate data>; var = value;}
          }    

          // does stuff like validates user ID, account, permissions, password, resets, etc.
    }
}


0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10827350


The above code shows a very simple design for a user and user type interfaces.  You will do the same thing for all of your objects (NOUNS) that require data to be moved from one point to another through various actions (VERBS).


Once that is done, it is now time to tie it all together (here is where I actually answer your question)


You create an abstract base application instance class all of your functional classes (VERBS) will inherit from this abstract application class, thus carrying with it all of the objects (NOUNS) by default.  

public abstract class AppInstance
{
    private User usr = new User();

    protected IUser UserInfo
    {
          get{ return user;}
    }

    protected IUserSecurity UserSecurity
    {
          get{ return user;}
    }

}


Now all of your classes that DO something will inherit this class as its base class.



      public class DoSomething: AppInstance
      {
            public DoSomething()
            {
                  this.UserInfo.FirstName;
                                                this.UserSecurity.Password;
            }
      }

NOTICE: that in the abstract class AppInstance I am returning the usr variable which is of type User, but the property is filtering out only the data that I want to use (UserInfo type).



0
 
LVL 22

Accepted Solution

by:
_TAD_ earned 500 total points
ID: 10827426



Obviously this is really long and takes a lot of forethought and planning, but believe me if this is a large project it will be worth it!

All this dancing around with Abstract classes and interfaces makes things look more complex (and it is), but if/when you get the project compiled it will function error free.  

From a design aspect, Interfaces move runtime errors to compile time so you will get more compile time errors, but fewer runtime errors.  

All in all, a good trade off in my estimation (it will save time on testing).  
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10827537


Here are a couple of links to programming design patterns

Designing Data Tier Components and passing data through tiers (60+ pages)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/BOAGag.asp


A list of Microsoft programmers Design Patterns and Best Practices (1,000+ pages)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/exceptdotnet.asp?frame=true
0
 

Author Comment

by:gvector1
ID: 10828063
TAD,

You have well earned these points and I gladly give them to you.  You have enlightened me quite a bit.  I still have quite a bit of comprehension to do, but it is coming.  I understand some but not all.  I will take a look at your links and practice with this.  I am building an Electronic Medical Records System.  That is why I need the code to be as efficient as possible.  I am kind of a neat freak.  I can't stand for my code to be sloppy and inefficient.  I normally write some code, go back and clean it up, write some more code, go back a clean it up.  Again, thanks for the info and here are your points.

Thanks,
Kendal
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10828257


Sure, not a problem.  If you have more questions or would like some more specific code examples feel free to contact me directly.  A variant of my email address is in my profile.  I know most everyone frowns on going 'outside' the forum with questions, but I think this thread has enough to get most programmers started in the right direction (which is the intent).  Anything more specific will require a bit more code (and probably a file transfer or two).


cheers!
0
 
LVL 3

Expert Comment

by:int_20h
ID: 10828311
_TAD_,
     I understand what you're saying in your post!  But I don't see how you can share the same class instance accross other classes?  So, if I have a Class A that creates an instance of DoSomething and provides information to set in DoSomething like the user first name and password.   Now, in Class B, I want to get the same user first name and password I set in Class A.  How is this data shared to Class B?
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10828355
Finally.....   Just for the sake of completeness, here is the file that I used when writing this example (to ensure my syntax was correct).  If nothing else, at least this gives you a complete look at something that will compile properly.


using System;

namespace Application1
{
      //IUserSecurity interface
      public interface IUserSecurity
      {
            int ID{get;}
            string Password{get;}
      }
      
      //IUser Interface
      public interface IUser
      {
            string FirstName{get;}
            string LastName{get;}
      }

      // User Class
      public class User: IUser,IUserSecurity
      {
            //constructor
            public User(){}
            //required by the IUser interface
            public string FirstName{get{return "TAD";}}
            public string LastName{get{return "Degen";}}
            //required by the IUserSecurity interface
            public int ID{get{return 1;}}
            public string Password{get{return "_TAD_";}}
      }

      // Abstract Base class
      public abstract class AppInstance
      {
            //declare variable
            private User usr = new User();
        //protected properties
            protected IUser UserInfo{ get{return usr;} }
            protected IUserSecurity UserSecurity { get{return usr;}      }
      }

      public class TestingClass: AppInstance
      {
            public TestingClass()
            {
                  // *****  DO STUFF HERE  *****
                  Console.WriteLine(this.UserInfo.FirstName);
            }
      }
}
0
 

Author Comment

by:gvector1
ID: 10828360
That is a very good straightforward question that I would also like the answer to.  If that is not possible, I need to know because that would present a problem for me.

Thanks,
Kendal
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10828427


int_20h>  Quite a few posts back I posted a set of rules (which I try to follow).

Rule 3 states:

3.     An instance of a class should not send messages directly to
components of another class. That is, if there is a class C defined inside
class B, then objects of a class A should not directly perform operations on
objects of class C (though many languages will permit it).



So in answer to yuor question, under my rules (which are stricter than most), Class B will never under any circumstances talk with class A.  At least not directly.


Instead we have BaseClass1 create an instance of Class A.  And, by design, BaseClass1 will contain a reference & interface to Class A (where the user was set).  BaseClass1 ALSO contains a reference & interface to Class B (which we now want to use).  When Class B wants the userId, it goes back to it's base class (BaseClass1) and requests, from BaseClass1, the information from Class A (which BaseClass1 interfaces with to get the data).


It sounds like a lot of work, but once you do it a few times it's hard to do it any other way.

also, if it helps at all I tend to think of OO programming like designing a tree.  All the data and bits and pieces that the users see are the leaves or branches.  As you get more and more generic with application tiers and data access components and data tiers... back to the begining of the program where it is most abstract you have the largest classes with the least amount of apparently useful code (the code in the generic classes looks a bit funny, most functions have only one line of code in abstract classes).
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10828453


To put another way... it is not like you are creating an instance of data in A and then want to use that data in B  (A -> B)


you are instead creating a base (parent) class that instantiates class A for you and then when B (which is also created by the parent class) needs data from class A, it simply calls back to the base class to get the data from the instace of A class that it created.
 
        Base
       /       \
 ClassA    ClassB


Neither Class A, nor Class B can exist if the Base class goes out of scope.
0
 
LVL 3

Expert Comment

by:int_20h
ID: 10828729
_TAD_,  Thanks for your explanation!!! So, with that analogy, if I want to create more classes that need the same data (ie userInfo), I need to create the instances in Base? Hence, if I have ClassC...ClassZ then all the instances will exist in Base?  Is my understanding correct?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 22

Expert Comment

by:_TAD_
ID: 10829289


int_20h>

More or less...  I suppose that is an accurate explanation.

In reality, you would really only have 4 or 5 clas instances in your base class (or fewer), but then your ClassA becomes the base class for ClassC and ClassD


                                                        Base
                                                       /       \
                                             ClassA           ClassB
                                             /                  /          \
                                       ClassC          ClassD         ClassE
                                      /         \
                                ClassF      ClassG  




To give you a more real life example, a while back I created a space invaders type game (crude graphics, crummy collision testing, but animation, control, and design were good).

                                              Cartesian
                                              /           \
                                        FrGnd        BkGnd
                                      /          \
                              Ships           Weapons    
                             /      \           /            \  
                     Aliens     Allied    Bombs     Missles


Cartesian class -  contained my cartesian coordinate system
BkGnd class - using the coordinates, it defined the boundaries (my space field or background)
FrGnd class - using the coordinate system, I define my abstract foreground objects (position, height, width, strength, speed, directionX, directionY, isAlien)
Ships class - sets values for items defined above and define new attributes for the ships (shield, numberOfShips)
Weapons class - sets values for some of the attributes defined by frGnd, creates new attributes (warHeadYield)
Aliens class - sets remaining attribute values and creates instances of aliens
Allied class - sets remaining attributes and creates a singleton instance of an allied ship
Bombs class - sets remaining attributes and creates instances of alien bombs
Missles class - sets remaining attributes and creates instances of allied missles



So you see, in a real situation, each object can be abstracted enough to allow some commonalities.  Furthermore, by abstracting back further and further you find that your base class does not contain 40 object instances.  Instead it holds two or three objects who inturn each hold another two or three objects, who in turn each hold another two or three object instances....etc, etc.


So in my invaders game... when I wanted to find out if my Missle killed an alien ship, I couldn't just take the coordinates of the missle and the coordinates of the alien and see if they had intersecting rectangles.  That would break my rules.

Instead I had my missle class go through the weapons class, which went through the foreground class which then walks down the ships class to the array of aliens class and itterates through the array of aliens to see if any of them have intersecting coordinates.


whew!  I hope this example puts things into perspective a bit more.
0
 
LVL 3

Expert Comment

by:int_20h
ID: 10833509
Great _TAD_, your invader project explanation clarifies it very well!!  Thanks for your time explaining it... Good job!
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10836144


int_20h>

    Thanks, I do what  can.   :-)

0
 

Author Comment

by:gvector1
ID: 10836370
TAD,

I hope I am not irritating you.  I have researched interfaces some to get a better understanding of them.  I have also studied your example above to get a better understanding of it as well.  I want to know if I understand it correctly and see if you can answer a few more questions:

The major benefit to using interfaces over straight classes is that you can use multiple inheritance with interfaces but you cannot with classes???????

Questions:
I follow your example above and understand it for the most part, but in my situation I think there are minor differences.

For the most part it looks as though the interfaces are along the lines of what I need, except that I will have to set the values at runtime.  Do I need to do that in the User Constructor by passing in the values and setting them there.  Here is the above code modified through my way of thinking.  Let me know if I am correct.

using System;

namespace Application1
{
     //IUserSecurity interface
     public interface IUserSecurity
     {
          int ID{get;set;}
          string Password{get;set;}
     }
     
     //IUser Interface
     public interface IUser
     {
          string FirstName{get;set;}
          string LastName{get;set;}
     }

     // User Class
     public class User: IUser,IUserSecurity
     {
         //constructor
          public User(string fname, string lname, int id, string pword)
                    {
                        this.FirstName = fname;
                        this.LastName = lname;
                        this.ID = id;
                        this.Password= pword;
                    }

!!!!!I lost it from this point.  Can you point me in the right direction!!!!!

?          //required by the IUser interface
?        public string FirstName{get{return "TAD";}}
?        public string LastName{get{return "Degen";}}
?          //required by the IUserSecurity interface
?          public int ID{get{return 1;}}
?          public string Password{get{return "_TAD_";}}
?     }

?     // Abstract Base class
?     public abstract class AppInstance
?     {
?          //declare variable
?          private User usr = new User();
?        //protected properties
?          protected IUser UserInfo{ get{return usr;} }
?          protected IUserSecurity UserSecurity { get{return usr;}     }
?     }

     public class TestingClass: AppInstance
     {
          public TestingClass()
          {
               // *****  DO STUFF HERE  *****
               Console.WriteLine(this.UserInfo.FirstName);
          }
     }
}

Since AppInstance is an abstract class that instantiates the user class, how do I get the runtime values to User constructor to set the values????  It appears that in order to have access to the User class, the AppInstance must be inherited......am I correct?????  

So on every form do I need to create a class that inherits AppInstance and that will give me access to my user values?????????  

Forgive me if I get on your nerves.  I am just trying to learn and understand everything I can.

Thanks,
Kendal
0
 

Author Comment

by:gvector1
ID: 10836513
I think I figured out a little bit more.  Still do not know about the abstract class that instantiates the user class.  

using System;

namespace Application1
{
     //IUserSecurity interface
     public interface IUserSecurity
     {
          int ID{get;set;}
          string Password{get;set;}
     }
     
     //IUser Interface
     public interface IUser
     {
          string FirstName{get;set;}
          string LastName{get;set;}
     }

     // User Class
     public class User: IUser,IUserSecurity
     {
          private string myfname, mylname, mypword;
          private int myid;

         //constructor
          public User(string fname, string lname, int id, string pword)
                    {
                        this.myfname= fname;
                        this.mylname = lname;
                        this.myid = id;
                        this.mypword = pword;
                    }

          //required by the IUser interface
          public string FirstName{get{return myfname;}set{myfname = value;}}
          public string LastName{get{return mylname;}set{mylname = value;}}
          //required by the IUserSecurity interface
          public int ID{get{return myid;}set{myid = value;}}
          public string Password{get{return mypword;}set{mypword = value;}}
     }

????How do I instantiate the user class with runtime values from an abstract class????
     // Abstract Base class
     public abstract class AppInstance
     {
          //declare variable
          private User usr = new User();
        //protected properties
          protected IUser UserInfo{ get{return usr;} }
          protected IUserSecurity UserSecurity { get{return usr;}     }
     }

     public class TestingClass: AppInstance
     {
          public TestingClass()
          {
               // *****  DO STUFF HERE  *****
               Console.WriteLine(this.UserInfo.FirstName);
          }
     }
}

Thanks,
Kendal
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10838794

First... to clear things up a bit.  Multiple inheritance is not supported at all by .Net.  You can INTERFACE many, many classes, but only inherit from one of them.  The distinct difference is that inheritance brings data into a class, interfaces gives you a consistant way to pull data out.

As for the abstract class... the very base class should be abstract, but that doesn't mean that that is the class you need to instantiate.

.net example:

                                          Stream
                                    /        |         \
                                /            |            \
               FileStream     MemoryStream    BinaryStream


Stream str = new Stream();             //ERROR!!

Stream str = new FileStream();        //OK
Stream str = new MemoryStream(); //OK
Stream str1 = (BinaryStream) str;    //OK



So you don't actually instantiate the abstract class.  However, this doesn't mean that you have to use an abstract class as your base class for the classes you want to use.


                                                    abstract
                                                         |
                                                      main
                                                    /        \
                                            Child1         Child2



public class Form1: Windows.Forms
{
     public Form1()
     {
           AppInstance myInst = new User();
     }
}






If this is real confusing, change your abstract class to a regular class.  And then use your class that way.  Once you get real familiar with this kind of set up you can always add an abstract class at a later date with virtually no effort.  That is the benefit of a setup like this... you can add and remove class structures on a whim as long as you stick to your rules and you won't "break" old code.

0
 

Author Comment

by:gvector1
ID: 10843186
Was I correct in my code above?  I can see how hard coded data is persisted throughout the application, but how do I persist runtime data.  Explain it to me from this aspect:

I login to my application and pull the user data.
Is my code for the User class correct as far as the constructor setting the values instead of being hardcoded?????????????????:
  // User Class
     public class User: IUser,IUserSecurity
     {
          private string myfname, mylname, mypword;
          private int myid;

         //constructor
          public User(string fname, string lname, int id, string pword)
                    {
                        this.myfname= fname;
                        this.mylname = lname;
                        this.myid = id;
                        this.mypword = pword;
                    }

          //required by the IUser interface
          public string FirstName{get{return myfname;}set{myfname = value;}}
          public string LastName{get{return mylname;}set{mylname = value;}}
          //required by the IUserSecurity interface
          public int ID{get{return myid;}set{myid = value;}}
          public string Password{get{return mypword;}set{mypword = value;}}
     }

I want to understand this abstract method, because it sounds like the best approach.
Now if I understand correctly, I don't actually create an instance of the User Class from my main code??????
From the examples above, the abstract class creates the instance of the User Class, but it seems that the only way that happens is by creating another class that inherits the abstract class.  If that is the case how can I get the User values to the User class through the new class I just created that inherits the abstract class.  After all that, since I am using forms, I basically create another form and show it.  How do I access that user data from say Form B, do I need to inherit the abstract class to form B also????????

Forgive me for being so bothersome.  After this is all said and done I would like to award you another 500 points for assisting me in understanding all this.  Once we are finished I will start another post that you can give a generic answer to and I will award you the points, just for all the trouble you have endured with me.

Thanks again,
Kendal

0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10845488


No.... No more points.  As long as I get my 10,000 points per month to maintain my "expert" status, I don't really care about the points.



As for your questions....


You are correct in your assesment that the only way to get an instance from the abstract class is to "hardcode" it (which I did in my example).  This is obviously not the preferred method to use in production.

to make the above example more viable for a production environment you'll need to make a few reference changes.

The class declarations will need to change slightly.


<FROM>
public class User: IUser,IUserSecurity

public abstract class AppInstance

<TO>
public class User: AppInstance

public abstract class AppInstance: IUser,IUserSecurity


The body of your abstract class will need to reflect the new properties that were added, and the body of class user can have those properties removed (or they can stay and override/hide the abstract class properties).


Now in your Form1_ButtonClick event you can code any of the following:

AppInstance a = new User();
User b = new User();
IUser c = new User();
IUserSecurity d = new User();

<You can add paramters to the User constructor as you see fit>



Object 'a' and 'b' will be 100% identicle in this particular example, UNLESS you using method overriding or method hiding.


Abstract classes are used mostly to keep your code looking neat/clean.  When you start getting into more advanced uses (method hiding or overriding) you will find that abstract classes have many more uses then just clean code.  For now however, that is all we are using it for.  


                                                    abstract
                                                         |
  WinForm1_ButtonClick------------>  Parent1
                                                      /     \
                                              Child1      Child2

<ButtonClick -- all will work>
Parent1 p = new Parent1();
Parent1 p = new Child1();
Parent1 p = new Child2();

abstract p = new Parent1();
abstract p = new Child1();
abstract p = new Child2();



The real power of abstract methods is that you add code ONCE to one place and then ALL child classes will have it.

Using this diagram:
                                                    abstract
                                                         |
                                                    Parent1
                                                    /        \
                                            Child1         Child2

Let's suppose that name of 'abstract' is 'ABS'

public abstract class ABS
{
      public FileStream f;       // I'll use public variables instead of properties for simplicity
      public BinaryStream b;
}

public class Parent1: ABS
{
    f = new FileStream();
    b = new BinaryStream();
}


// Child 1 and Child2 might look similar



Now that all of this is done, you realize that you cannot Kill your objects (no Dispose)!!   You could go through all of your classes and fix it (and hope you fix all of your classes)...

OR

Make the change in one place, the abstract class:


public abstract class ABS: IDisposable
{
      public FileStream f;       // I'll use public variables instead of properties for simplicity
      public BinaryStream b;

      public void Dispose()
      {
           if (f!=null) { f.close(); f.Dispose(); }
           if (b!=null) { b.close(); b.Dispose(); }
      }
}


Now *ALL* of your child classes (parent1, child1, child2) will properly dispose of these objects.



Okay... backtrack a little, and make sure I got all of your questions:

1) do not 'hard code' an instantiation in the abstract class, but rather instantiate the child class directly using the interfaces (IUser, IUserSecurity) to expose only the proper methods that you want available.

2) as for how Form B gets the User information.  You probably wouldn't want to inherit the abstract class inside your form class.  In fact, you wouldn't be able to (that would be mulitple inheritance).  Instead, you can INTERFACE your form class with one or both of the IUser/IUserSecurity interfaces.   You would then need to create the proper functions/properties in your FormB in order to get it to compile and pass values directly to your formB.


I know this is difficult to understand (I feel like I'm talking in circles).  It is really one of the most complex concepts of programming and I fear I am not doing a very good job articluating the nuances.

In short, abstract classes and interfaces are meant to be used only as templates.  Only classes can be instantiated and actually do work.  Abstract classes and interfaces are used primarily for controlling and have a secondary effect of forcing programmers to program in a uniform manner.


In another example we'll say we have an abstract class of animal, and all animals have ILegs, IEyes, ICoveringType

public abstract Animal:  ILegs, IEyes, ICoveringType {int LegCount (req'd by ILegs), enum EyeType (req'd by IEyes); }

public Interface ILegs{ int LegCount; <property get/set>}
public Interface IEyes{ enum EyeType; <property get/set>}

public class Mammal: Animal
public class Reptile: Animal
public class Bird: Animal
public class Fish: Animal
public class Insect: Animal
public class Other: Animal

public class Monkey: Mammal
public class Dog: Mammal
public class Pheasant: Bird
public class Snake: Reptile
public class Ant: Insect


Public class Ant: Insect
{
       public Ant()
       {
            this.LegCount = 6;
            this.EyeType = EyeTypeEnum.CompoundEyes;
       }
 
}


(Obviously the eyetype enum is not specified here and the ILegCount interface is not show either, but as you can see, the generic solutions provide a lot of flexibility)


You can further shift things around... like you don't NEED to declare each insect animal as having six legs.  Since we know that ALL insects have 6 legs, we can move that declaration up a level from the ANT class to the Insect Class, and then all Insect objects from here on out will automatically have 6 legs.

and since no mammal will ever have compound eyes, we can actually hide that value when we get to the Mammal class, so no child objects (Dog, cat, horse, etc) will have Compound Eyes available to them as a choice.

The power of the abstract class is that we can declare a generic high level variable that we can dispose of in a generic way, but can handle the specifics later.


Something like this:

<Windows Form1 Numeric Key Press Event>

Animal myCritter;
 
      switch(numPressed)
      {
            case(1):
                 myCritter = new Mammal();   // more specific, but still generic
                 break;
            case(2):
                  myCritter = new Dog(); // most specific
                  break;
             case(3):
                  myCritter = new Ant();  // most specific
                  break;
              default:
                  myCritter = null;
                  break;
       }

string covering = myCritter.BodyCovering;
string eyes = myCritter.EyeType;
int legs = myCritter.LegCount;

myCritter.Dispose();



you *MUST* use the actual class to create the instance of the object, but you can use the abstract class to create a reference to the new object before you actually know what you want to do with it.
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10845560


Interfaces work the same way.  In fact I actually use them quite often when connecting to databases

public class ConnectToDb
{

IDbConnection myConn;

   public ConnectToDb(string connStr)
   {
            if(connStr.SubString(0,3)=="Sql")
                   myConn  = new SqlDbConnection(connstr);
            else
                   myConn = new OleDbConnection(connstr);
    }
0
 

Author Comment

by:gvector1
ID: 10845616
The way it looks to me is that the only way to get the same values throughout multiple classes is to hardcode them in the abstract class, otherwise I will need to set the values through the class that inherits the abstract class??????
0
 
LVL 22

Expert Comment

by:_TAD_
ID: 10847471


you really don't want to hardcode them into the abstract class.  There are ways around doing that (in part, that's what iterfaces are for).  

However, before we start jumping through more hoops than we need to, let's take a brief look at a project that you have in mind.


You've got two forms and you want to save User data to a database.

First and foremost, with the advent of data connection pooling, you'll want to open and close the connection for each transaction.  This biggest reason for this is that some DB's you purchase licenses by the "seat" and other databases only allow a set number of concurrent users.  If you open and close the connection with each transaction, even a large web site with 1,000's of transactions per day can get by with 50 licenses.



Passing data between Forms is very easy, you simply instantiate a class in one form and if you need to pass data back and forth, you find the constructor of Form2 and make the class a parameter.  If you don't want to force it, you can use method overloading.

locate the function

public void Form2()

and change it (or add a new function)

public vod Form2(UserData myUser)
0
 

Author Comment

by:gvector1
ID: 10859310
I am currently using a MySql Database.  I have users set up in the database that I check against.  What I am doing is on my login screen, I check the database for the user and password that are entered on the login screen.  If they exist I want to load them and the other fields from that record in the database into a class, or something of the sort, that is persisted throughout the application.  That way on certain forms, based on some of the values of that class, I can give access to the user to do certain things.  It is basically to restrict access of users.  I knew I could pass the class as a parameter to other forms, but I figured there might be a way to persist an instance of the User class that I can use throughout the entire application without passing parameters and having to know certain user values each time I need to instantiate the class.  I gave a try to the singleton approach posted by int_20 and it works exactly as I would like.

By the way int_20.  Since I was able to make use of your suggestion and it works great, i would like to award you some points as well.  Let me know when you read this message and I will start another post in order to award you some points as well.

Here is the singleton that I defined

public class User
      {
            private static User instance = null;
            static readonly object padlock = new object();

            private string mID = "", mPass = "";

            private User()
            {
            }

            public string ID
            {
                  get{return mID;}
            }

            public string Pass
            {
                  get{return mPass;}
            }

            public static void setInstance(DataRow dr)
            {
                  if (instance==null)
                  {
                        lock (padlock)
                        {
                              if (instance==null)
                              {
                                    instance = new User();
                                    instance.mID = dr["user"].ToString();
                                    instance.mPass = dr["password"].ToString();
                              }
                        }
                  }
                  
            }
            public static User getInstance()
            {
                  if (instance==null)
                  {
                        lock (padlock)
                        {
                              if (instance==null)
                                    instance = new User();
                        }
                  }
                  return instance;  
            }
      }

This way on the login screen I call User.setInstance with the datarow I pulled from the database.  It loads the members into the class instance.  Then anywhere throughout the application I just call User myUser = User.getInstance() and I will have an instance of the user class with all the values I need loaded.  If I do the same thing with interfaces and abstract classes, I would like to know how.  I like to learn as much as I can.

Thanks a million,
Kendal
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11053494
Was reading my old responses to the ones I didn't get points to see how people got around it... I see you did use the Singleton Pattern afterall....  If you fell compell to award me with points, I appreciated!  :)

I picked up a great design patterns in C# last month and it's amazing!, I'll recommended to whoever wants to learn about design patterns... Anyway, here is an improved version of the singleton that totally avoid issues with deadlocks and compilers smartness!!!

// .NET Singleton
sealed class Singleton
{
    private Singleton() {}
    private static readonly Singleton Instance = new Singleton();

    public getInstance()
    {
        return Instance;
    }
}
0
 

Author Comment

by:gvector1
ID: 11053584
int_20h,

I will start a post titled singletons.  If you would post your last message to this post I will award you the points.  I would just like to give credit everywhere it is due.

Thanks again,
Kendal
0
 

Author Comment

by:gvector1
ID: 11053736
With the latest singleton example you gave, how would I go about setting the initial values that are only known at runtime????

Here is how I am defined right now:

public static User setInstance(string sUser)
{
      instance = null;
      lock (padlock)
      {
            if (instance==null)
            {
                                   MySQL sql = MySQL.getInstance();
                  DataRow drUser = sql.PullUser(sUser);

                  if(drUser != null)
                  {
                        instance = new User();
                        instance.mID = drUser["userid"].ToString();
                        instance.mFirstName = drUser["fname"].ToString();
                        instance.mLastName = drUser["lname"].ToString();
                        instance.mMInit = drUser["minit"].ToString();
                        instance.mSSN = Convert.ToInt32(drUser["ssn"]);
                        instance.mSex = drUser["sex"].ToString();
                        instance.mAddress1 = drUser["address1"].ToString();
                        instance.mAddress2 = drUser["address2"].ToString();
                        instance.mCity = drUser["city"].ToString();
                        instance.mState = drUser["state"].ToString();
                        instance.mZip = Convert.ToInt32(drUser["zip"].ToString());
                        instance.mHomePhone = Convert.ToInt32(drUser["homephone"]);
                        instance.mWorkPhone = Convert.ToInt32(drUser["workphone"]);
                        instance.mTitle = drUser["title"].ToString();
                        instance.mStartScreens = drUser["startscreens"].ToString();
                  }
            }
      }                  
               return instance;
}

Could that be converted to use the new Singleton approach?

Thanks,
Kendal
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11053996
This is how I would do it!
sealed class User
{
    private static readonly User instance = new User();
    private string mID = null;
    private string mFirstName = null;
    ...// for every variable that you want to set in the constructor
    ...

    private Singleton() {
          MySQL sql = MySQL.getInstance();
        DataRow drUser = sql.PullUser(sUser);

        if(drUser != null)
        {
                mID = drUser["userid"].ToString();
                mFirstName = drUser["fname"].ToString();
                mLastName = drUser["lname"].ToString();
                mMInit = drUser["minit"].ToString();
                mSSN = Convert.ToInt32(drUser["ssn"]);
                mSex = drUser["sex"].ToString();
                mAddress1 = drUser["address1"].ToString();
                mAddress2 = drUser["address2"].ToString();
                mCity = drUser["city"].ToString();
                mState = drUser["state"].ToString();
                mZip = Convert.ToInt32(drUser["zip"].ToString());
                mHomePhone = Convert.ToInt32(drUser["homephone"]);
                mWorkPhone = Convert.ToInt32(drUser["workphone"]);
                mTitle = drUser["title"].ToString();
                mStartScreens = drUser["startscreens"].ToString();
        }
        else
                throw new Exception();  
    }
   
    public static User getInstance()
    {
        return instance;
    }
}
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11054006
oopss... it should be:

private User() {
...

}
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11054009
Thanks for the point! :)
0
 

Author Comment

by:gvector1
ID: 11054064
I think I can work with that, but I think you left the sUser Parameter out of the constructor call.
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11054090
oh if you are receiving the sUser as parameter you should be ok doing what you're doing!  :)  but the method should be getInstance rather than setInstance since you're getting the instance!
0
 

Author Comment

by:gvector1
ID: 11054132
On my login screen is where I call setInstance with the login information.  Throughout the rest of the application I call getInstance() to retrieve the information, because there is only one time(LOGIN) that I will have to set the information.  So should I leave it with the deadlock code or modify the code accordingly?

Thanks,
Kendal
0
 
LVL 3

Expert Comment

by:int_20h
ID: 11054154
Just leave it with the Lock...  You'll not have any problems since you instanciate it from the beginning of the app via single form (login form)... plus you don't have any multithreaded issue at that time... you should be good with the code you showed in here! :)  Happy coding!
0
 

Author Comment

by:gvector1
ID: 11054170
Thanks
0
 

Expert Comment

by:vanwieringenm
ID: 20932086
TAD
I spent a great deal of time going over this post to understand the most effective means of accessing an object across various forms. Also, googling results in a ton of information regarding why or why not for using a singleton. I have an application which is a MDI windows app c# which has a number of forms that share information. A couple of form that I am working on use a employee class which when done via a singleton works as expected both form see updates and data changed in each form. This issue is that I really do not need to have the class exist for the lifetime of the application. Once the class is done being used I would like ot clean up. I have be able to create the class in the MDI form and passed the class to the forms as you directed a number of posts above. The result is the same however I believe that this is more in the spirit of OOP. My issue is trying to clean up. Should the MDI periodically check to see if there are multiple instances of the class and once there is only 1 (the MDI form) clean up?
Also the application is broken into 3 layer, presentation, business and dataaccess. Currently, when a form that requires needs the employee class it the MDI form calls the business layer to create the employee class collection, which in turn calls the DA to get the Dataset to build the class. The employee class collection is then passed to the child form to use.
Is this approach recommended?
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now