Click here to Skip to main content
Click here to Skip to main content

N-Tiered Programming with VB.NET Interfaces and Singletons

, 27 Jul 2006
Rate this:
Please Sign up or sign in to vote.
An article on using .NET Interfaces and a Singleton (a class that will only have one instance in memory at any time) to abstract the different layers in an N-tiered application.

Sample Image - InterfacesAndSingletons.jpg

Introduction

This article is meant to illustrate a design concept in which a singleton is used to abstract one layer from the next in an N-tiered system. This is a general design concept illustration with an actual code based example. This article is also meant for intermediate to advanced programmers who understand VB.NET and some of the more advanced capabilities of the language and compiler.

Background

The Singleton

The first thing that you must understand to use this design technique is the concept of a singleton. A singleton is a class that is built in a way that prevents the creation of multiple instances of itself in memory.

As illustrated above, when using a normal class, each user would create an instance of it in memory. However, with a singleton, User One would create an instance of the class and then User Two would receive a handle to the same class. This decreases the amount of memory required as well as the processor time required for the call since the object does not have to be built.

Imports System.Runtime.CompilerServices

Public Class ImplementationLocator
    'Create a reference of type ImplementationLocator (myself)
    Private Shared myInterfaceClass As ImplementationLocator

    'Hide the New constructor from the outside world
    Private Sub New()
    End Sub

    'Syncronize the whole method to make sure there will not be two
    'instances created due to threading and OS ordered sleeps
    <MethodImplAttribute(MethodImplOptions.Synchronized)> _
    Public Shared Function GetInstance() As ImplementationLocator
        'Check to see if the private object has been created yet
        If myInterfaceClass Is Nothing Then
            'If the object has not been created, create one
            myInterfaceClass = New ImplementationLocator
        End If

        'Send back a handle to the private object
        Return myInterfaceClass
    End Function

    Public Function GetVINA(ByVal CarCode As String) As IVehicleQuery
        Select Case CarCode
            Case Constants.CarCodes.Chevy
                Return New implChevyVehicleQuery
            Case Constants.CarCodes.Ford
                Return New implFordVehicleQuery
            Case Constants.CarCodes.Dodge
                Return New implDodgeVehicleQuery
            Case Else
                Return Nothing
        End Select
    End Function
End Class

There are three things required to create a singleton in VB.NET. You must first create a Private Shared reference to the class. Do not use a New constructor in this call. The second is you must hide the New constructor from everyone except the class itself by declaring it Private. The last thing you must do is create a function that will return the Private Shared instance from the first step. This function must be Public Shared. You must also synchronize the whole method (my preferred way of doing it), or use SyncLock. If you decide to use SyncLock, the function would look like this:

Dim objLock as Object
Public Shared Function GetInstance() As ImplementationLocator
    'Check to see if the private object has been created yet
    If myInterfaceClass Is Nothing Then
        SyncLock(objLock)
            If myInterfaceClass Is Nothing Then
                'If the object has not been created, create one
                myInterfaceClass = New ImplementationLocator
            End If
        End SyncLock
    End If

    'Send back a handle to the private object
    Return myInterfaceClass
End Function

The key portions of this code are the creation of an object to hold the lock and the fact that we check to see if myInterfaceClass has been created just before the lock and just after the lock. This is due to threading problems and the unpredictable nature of OS sleep calls.

The Interface

An interface in .NET is similar to a class. Both declare properties, methods, and events. An interface, however, does not have any implementation in itself. In other words, an interface is nothing but a signature file. Those of you that know C would be semi-familiar with this. In C, you must declare the signature of all functions at the top of the file. A .NET interface simply takes these declarations and puts them in a separate file. A class can then implement an interface by implementing all of properties, methods, and events laid out in the interface. Generally, only Public and Friendly items are put in an interface.

Public Interface IVehicleQuery
    Function GetModelByVIN(ByVal strVIN As String) As String
    Function ValidateVIN(ByVal strVIN As String) As Boolean
End Interface

The Implementation

Now that there is an interface, there must be classes that implement it for it to be of any use. Here are three classes that implement IVehicleQuery:

Public Class implFordVehicleQuery
    Implements IVehicleQuery
    Public Function GetModelByVIN(ByVal strVIN As String) _
           As String Implements IVehicleQuery.GetModelByVIN
        Return "Mustang"
    End Function

    Public Function Validate(ByVal strVIN As String) _
           As Boolean Implements IVehicleQuery.ValidateVIN
        Return True
    End Function
End Class

Public Class implChevyVehicleQuery
    Implements IVehicleQuery
    Public Function GetModelByVIN(ByVal strVIN As String) _
           As String Implements IVehicleQuery.GetModelByVIN
        Return "Nova"
    End Function

    Public Function Validate(ByVal strVIN As String) _
           As Boolean Implements IVehicleQuery.ValidateVIN
        Return True
    End Function
End Class

Public Class implDodgeVehicleQuery
    Implements IVehicleQuery
    Public Function GetModelByVIN(ByVal strVIN As String) _
           As String Implements IVehicleQuery.GetModelByVIN
        Return "Charger"
    End Function

    Public Function Validate(ByVal strVIN As String) _
           As Boolean Implements IVehicleQuery.ValidateVIN
        Return True
    End Function
End Class

Note that just below the class declaration, we have an “Implements [Interface Name]”. After each function, there is an “Implements [Interface Name].[Function Name]”. You may additionally add other methods and properties that you choose. The only requirement is that you at least include all of the items defined in the interface.

Using the Code

The purpose of the singleton in this case is to return an implementation of an interface. The only thing that the UI layer needs to know is the interface. Any class that implements that interface can be returned to an object of type Interface. It's easier to look at the code:

Private Sub btnLookup_Click_1(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnLookup.Click
    'Check to see if the user entered a VIN
    If TextBox2.Text <> "" Then
        'Get Car Code from the enum in the Constants file
        Dim myCarCode As String
        If RadioButton1.Checked Then
            myCarCode = Constants.CarCodes.Chevy
        ElseIf RadioButton2.Checked Then
            myCarCode = Constants.CarCodes.Ford
        Else
            myCarCode = Constants.CarCodes.Dodge
        End If

        'Get an object to Implements IVehcileQuery
        Dim objVehicleQuery As IVehicleQuery
        objVehicleQuery = ImplementationLocator.GetInstance().GetVINA(myCarCode)

        'Always check objects when you don't construct them yourself
        If Not objVehicleQuery Is Nothing Then
            TextBox1.Text = objVehicleQuery.GetModelByVIN(TextBox2.Text)
        End If
    Else
        'If no vin was entered, inform the user they need one.
        MessageBox.Show("Please enter a VIN", "No VIN Entered")
    End If
End Sub

The important pieces of code in the above example are:

'Get an object to Implements IVehcileQuery
Dim objVehicleQuery As IVehicleQuery
objVehicleQuery = ImplementationLocator.GetInstance().GetVINA(myCarCode)

'Always check objects when you don't construct them yourself
If Not objVehicleQuery Is Nothing Then
    TextBox1.Text = objVehicleQuery.GetModelByVIN(TextBox2.Text)
End If

First, an object is made of type IVehicleQuery. Then, we get an instance of the singleton using the GetInstance method. From the returned object, we call the GetVINA() method, passing it myCarCode. The object returned depends on the value of myCarCode. As long as the object implements IVehicleQuery, it is a legal operation.

Credits

Special thanks goes out to Jeff Corn and David Shelton for introducing the concept to me.

History

None to date.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Jeremy Beckham
Web Developer
United States United States
I am a Senior Developer with High Power Consulting, and a student in the Information Systems and Decision Sciences program at LSU in Baton Rouge.
Currently working primarily with the Microsoft .Net Framework and T-SQL, I have significant experience with C programming in Unix and Linux environments. I also have expertise in PERL, VB 6, VBA for Reflection, VB.Net, C#, and Java, and I specialize in integrations and Service Oriented Architecture as well as n-Tiered architectures.

Comments and Discussions

 
GeneralNice Article Pinmemberidoapps31-Jan-07 11:28 
QuestionDependancy Injection? PinmemberJohnDeHope325-Jul-06 3:04 
AnswerRe: Dependancy Injection? PinmemberR Sexton7-May-07 3:27 
GeneralRe: Dependancy Injection? PinmemberJohnDeHope37-May-07 11:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140718.1 | Last Updated 27 Jul 2006
Article Copyright 2006 by Jeremy Beckham
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid