User Login





Register
Forget Password

Hostings with very low prices

Hosting Plans Starting at 1$/Month

BaydHost

Powered By

  • AhmBay
  • Object Oriented Design Principles in Visual Basic - ASP Webmaster Tips, Knowledge Base Webmaster Tools

    Home > ASP > Object Oriented Design Principles in Visual Basic
    Category: ASP
    Written by: Admin
    Date: 2008-11-10
    Rating: 0   Puan:0 | Katılımcı:0 | Voted : 0 times
    Hit: 333
      

    Object Oriented Programming (OOP) is more than just a programming concept. It is a way of thinking about applications. It is learning to think of applications not as procedures, but objects and real entities. That makes a lot of sense. We view the world around us not as intangible, but as real entities or objects. Objects that do things (methods), and have things (attributes). They are logically grouped by the way they appear and behave. Cars may differ in cabin space, color, engine size, acceleration, yet they’re all similar in form and function. If we think of our physical world in that way, why not code?



    In programming, an object is a run time instance of code and data that comprise some sort of logical grouping, usually referred to as a business entity. Suppose you hated that ugly palm in your yard and wanted to replace it with a newer one, or maybe even an oak? You wouldn’t tear up you entire yard, trying to uproot that tree. That’s precisely one of the most prevailing advantages to OOP, namely to reusability. Imagine that you didn’t have to sift through lines of code to change some obscure variable. Imagine that you could add new functionality to your application by pulling out an object, changing it, and plugging it back in. Another great advantage is improved code readability, reliability, and adaptability. What if you wanted to create an entirely new type of code object, say, a supervisor, that had all the same functionality as an employee, but had more security rights, or maybe even a different pay scale? Other developers do not need to know how an object does what it does, just how to make it do it. You don’t have to know how a car works, just where the brake and gas are.



    The mere fact that code may contain properties (attributes) and methods, does not, in itself, make it object oriented. To illustrate; a COM component may contain several functions that calculate totals and retain certain values. Such a component may be an object because it is an instance of a class, but it is not object oriented, since it does not follow many of the ideals of OOP.



    In Visual Basic, as do many other languages, we use classes to define components. Once created, and populated with data, a class becomes an object with properties and methods, not just a prototype or code. So far, so good, Visual Basic can do classes with properties and methods.



    While it is debatable whether OOP works in all situations, we’re only going to cover one case study where it does. Essentially, we’ll briefly explain four main object oriented design concepts: Inheritance, Polymorphism, Aggregation, and Encapsulation (containment). There are also other aspects, such as overloading, delegation, etc., which we won’t cover in too much depth.



    Before we begin, we must define an interface. An interface is basically a signature of what the code component does. It’s a contract that you can’t break, but can amend. Once we agree what a car is, we can’t change it’s definition to define a motorcycle.



    Inheritance
    Inheritance allows one class to inherit the functionality of another without having to rewrite the code. In genetics, a child has some of the traits of a parent, while still functioning and appearing quite unique. Inheritance as a programming concept works the same way. An inherited class should contain all of the implementation of its parent class (superclass, base class, etc.) through its inherited interface.



    There are various types of inheritance. Interface inheritance, inherits only the interface signature, while implementation inheritance inherits the actual code implemented in its parent. Visual Basic, and COM for that matter, do not support implementation inheritance. But they can simulate it using aggregation (actually delegation), which we’ll discuss later. Visual Basic does though, support interface inheritance. This is accomplished by adding interfaces, written in IDL, to an ActiveX DLL. Visual Basic does this for you when you use the implements keyword. COM does allow multiple interface inheritance, but each object instance can only communicate through one interface at a time (that’s a good thing). To illustrate, let’s look at the following pseudocode.


    Class 1 Interface 1
    Method1()
    Class 2 Interface 2 inherits Interface 1
    Method2()
    Method1()

    Method 1 of interface 2 is actually contained in the code for class1. Can Visual Basic do that? Yes… no… well, kind of. We can simulate it, and we’ll do that using a variety of other OOP techniques.



    Polymorphism
    Polymorphism is accomplished when different components or classes behave differently to the same interface. Think of it as more than one way to code an identical method. What one component does in its Update method may be different than what another may do, or need to do. We implement polymorphism in Visual Basic, by overriding methods. When several objects must support the same interface, we rewrite the method each time. Consider the following code.



    Object 1


    Implements ITest
    Private Sub ITest_Update(strData as String)
    ‘Update Test Database
    End Sub

    Object 2


    Implements ITest
    Private Sub ITest_Update(strData as String)
    ‘Send an Email
    End Sub

    Notice that object 1 and object 2 both implement the ITest interface, yet both implementations of the update method differ. Object 1 requires the update method to write to the database, while object 2 requires it to send an email. Polymorphism is the simple mechanism used to solve both scenarios while using same interface.



    Aggregation and Encapsulation
    Aggregation is a sort of symbiotic relationship between objects. In Aggregation, a host object acts as a liaison between the outside world and an inner object. This can be accomplished in several ways. One is by having both objects implement the same interface. Since they contain the same interface, when a host object is called, it can in turn make a call to the inner component’s same method (delegation), in effect, forwarding the call. Another technique allows the method of the inner component to be directly exposed to the outside world (aggregation). An object takes the inner object’s interface, and presents it as it own. Many times the relationship, not the specific technique is referred to as aggregation. Consider the following example.



    Object 1


    Private Object2 as Object2.ProgID
    ...
    Private Sub Class_Initialize()
    Set Object 2 = New Object2.ProgID
    End Sub

    Private Sub Class_Terminate()
    Set Object 2 = Nothing
    End Sub

    Public Function GetValue(intID as Integer) as String
    GetValue = Object2.GetValue(intID)
    ‘We can even add more functionality here
    End Sub

    Object 2


    Public Function GetValue(intID as Integer) as String
    ‘Get Value from Database
    ‘Set GetValue = the returnable string
    End Sub

    Object 1and object 2 both contain a method named GetValue. Notice though, that the implementation exists in Object 2. Object 1 aggregates the functionality of Object 2 by creating a private copy and calls its method internally, presenting it as its own. This allows Visual Basic developers to create more reusable components. We don’t have to name the methods the same, it’s the functionality we’re interested with here. Object 2 is only accessible through object 1. Notice that we can even add additional implementation to the GetValue method of Object 1.




    Encapsulation
    Encapsulation is a method of data abstraction that allows us only to change data through a representation, not the real thing. In Visual Basic, we can accomplish this using properties and methods. To illustrate, consider the code below.


    Private mintEmployeeNumber as Integer

    Public Property Get EmployeeNumber() As Integer
    EmpoyeeNumber = mintEmployeeNumber
    End Property

    Public Property Let EmployeeNumber(ByVal intNewValue As Integer)
    mintEmployeeNumber = intNewValue
    End Property

    Notice that you can modify employee number data only through the property Get EmployeeNumber and Let EmployeeNumber, but not by accessing the mintEmployeeNumber variable directly. We have made it somewhat more difficult to change the data, but more importantly, we have made a more reliable component because any changes to the data come through a very strictly typed process. Properties are not the only way we encapsulate data. We can also do this by calling methods, using user defined types (UDT), collections, variant arrays, and other methods.



    Other OOP Principles
    Overloading allows us to provide multiple procedures that have the same name and do similar things. You may rightly ask, “Isn’t that similar to polymorphism?” Well, yes and no. You can accomplish similar results. Recall that polymorphism allows varying functionality of the same interface.



    Overloading allows varying functionality of the same method by providing more than one signature. For example, with both methods, you could create several objects that have the same interface and different implementation, but with overloading, you can accomplish this in a totally different means. Instead of overriding, thus rewriting the method for each object, you could provide several methods named the same, but with different parameters in the same interface. Notice the following pseudocode.


    Public Function GetEmployee(strName As String) As Variant
    End Function

    Public Function GetEmployee(lngID As Long) As Variant
    End Function

    Public Function GetEmployee(dtStartDate As Date) As Variant
    End Function

    How do you do that in Visual Basic 6? Well, unfortunately you can’t. The code sample below is as close as we can get, but Visual Basic just doesn’t support overloading methods.


    Public Function GetEmployeeByName(strName As String) As Variant
    End Function

    Public Function GetEmployeeByNumber(lID As Long) As Variant
    End Function

    Public Function GetEmployeeByDateOfHire(dtStartDate As Date) As Variant
    End Function

    Architecting a Case Study
    Many times in web development, we need users to register to use our site. Suppose that you wanted to create a truly reusable process to use with other projects, or that your business rules change often. It may even be that your site offers an a la carte service with various different, or yet unknown, offerings. How can these goals be accomplished using Visual Basic 6?



    Case Study
    “Better Cottages and Flowers” magazine needs their web site to collect user data, thus allowing them to opt to receive newsletters, buy gardening tools, buy magazine subscriptions, place ads, gain access to the site for research, and many other things. They will also constantly be adding new monthly specials.



    Here are the business rules:



    Users emails must be recorded to receive the monthly newsletter;
    Users can register for access to their research site;
    Users can purchase products such as gardening tools and their profiles and information are stored;
    Users can purchase their annual paper magazine subscriptions;
    Advertisers can submit advertisement requests.
    June’s special is 10% off an annual subscription
    July’s special is join the newsletter and you get your choice of either
    August’s special is get a garden credit card and get a 50% off a subscription and a free pot
    Marketing has not come up with September-May offers yet.
    June-August offers are subject to change depending on market prices and availability.


    Occasionally, they may partner with other vendors, and there may be specials depending on the customer/site that referred them, or coupons.


    When we analyze the business requirements, we can see that they are all essentially forms of registering.



    The Traditional Approach
    Simple, create a web site with a page, component, and messy data structure for each offering. Code a method for each business rule, perhaps as done below.


    Public Function SignupforNewsletter(ByVal sEmail As String)
    'Add them to the database
    End Function

    Public Function BuyGardeningTools(ByVal sFirstName As String, ByVal
    sLastName As String, ByVal sAddress As String, _
    ByVal sCity As String,
    ByVal sState As String,
    ByVal sZipCode As String,
    ByVal lCreditCardNumber As Long, _
    ByVal dtExpirationDate As Date)

    'Add them to the database
    'Charge their card
    'Send authorization to shipping department
    End Function

    Public Function SubscribetoMagazine(ByVal sFirstName As String, ByVal
    sLastName As String, ByVal sAddress As String, _
    ByVal sCity As String,
    ByVal sState As String,
    ByVal sZipCode As String,
    ByVal lCreditCardNumber As Long, _
    ByVal dtExpirationDate As Date)

    'Add them to the database
    'Charge their card
    'Send authorization to fulfillment center
    End Function

    And so on…



    What happens when you need to add September’s promotion? We’d have to add it to the DLL and recompile, or create a new one. You can see that in no time, it will get ugly.



    The OOP Approach
    One design could allow for a common “registration” interface (we’ll call it IRegister) that all of our different types could inherit from. As long as all server objects support that interface, clients would call the objects seamlessly. Since there is little code that is in common, implementation inheritance is not needed here.



    Since Visual Basic doesn’t support the purist’s definition of inheritance, we can simulate it with the addition of polymorphism. We’ll start with a singleton classfactory pattern to achieve our desired result. A singleton is an object that will exist in only one instance. A classfactory is a special type of singleton whose job is to create other types of objects. A true classfactory would return a single interface.



    We mentioned that we don’t need implementation inheritance here. If we did require it, we could simulate it by placing common code in its own COM object and exposing its methods to a host object through the IRegister interface. The diagram below shows us the relationship that our processes will have. ASP pages will only interface with the classfactory, which will in turn, interface only with IRegister components.



    IRegister component

    This sequence diagram shows us the order of events. The ASP page gathers the information, and then calls the classfactory, which creates the appropriate IRegister component, and so forth. Only the classfactory’s interface will be exposed to the client. Every object that supports the IRegister interface will be created by the classfactory. In this case, we won’t return the component (or reference to it). We’ll instead do our business and return a Boolean result, and raise an error, which will be handled by the classfactory.



    One predicament though, is that these different registration types require different parameters. We can handle this in a variety of ways.




    Since we need to call these components from ASP, we’ll need to make sure that we hand classfactory the data that our IRegister objects need in a generic format. We could overload the IRegister methods to handle each of our requirements, but since Visual Basic doesn’t support overloading, we’ll use XML. This will accomplish two things.



    We can pass each IRegister object the specific data it requires without overloading methods
    We have effectively encapsulated our data using XML.


    XML can be passed around in a variety of forms, a string, SAX, DOM, and almost any other method you’d like. XML has definite advantages over passing around collections, recordsets, or arrays. The string form of XML can be passed around, while the object form is used in the code component. Since our clients are web pages, in many cases, IIS may be out of process with our DLLs, so we can avoid having to marshal objects. In addition, web pages are simple mechanisms for transporting XML.



    By using XML, we may even notice a performance increase. The drawback to this technique is that we do not have strong typing and it’s a little more difficult to follow the implementation.



    Under the covers, since ASP will be our classfactory’s client, and scripting only supports late binding, we’ll need to use the COM IDispatch interface. Not a problem since Visual Basic does this for us, in fact it does this for all ActiveX DLLs. Since our IRegister objects will be called by classfactory, we can use early or vtable binding using COM’s IUnknown. Visual Basic hides interface information (IDL) completely from the developer.



    Coding the Components and Interfaces.
    The IRegister Interface
    We’ll start with our IRegister interface, since it’s the heart of our application. We’ll define it as follows.



    IRegister


    Public Function SignUp(strXML As String, _
    Optional ByVal strConnection As String) As Boolean
    End Function

    We’ll place that in a class called IRegister. Fairly simple, it has two parameters. strXML, which is simply a large string containing XML.



    Note: you’ll need MSXML 3 for this demo.



    We won’t use a DTD in our example, but you could just as easily use SAX to generate it and the XML. An IRegister object receives an XML string by reference and does with it as it wants. The next parameter is strConnection, which is our database connection string. It is optional, because not all components will need to connect to the database. A better way may be to use Microsoft Transaction Server’s Shared Property Manager and load the connection string in ASP’s Application_OnStart event in the global.asa file. We could then omit this parameter altogether. But again, let’s keep this example simple. Finally, it returns a Boolean value to signal a success or failure.



    The Classfactory
    Now, let’s code the classfactory. Here’s the code.



    Classfactory


    1: Public Function DoRegistration(strXML As String, ByVal strProgID As
    String, _
    Optional ByVal strConnection As String) As Boolean
    2: On Error GoTo errHandler
    3: Dim objRegister As IRegister
    4: Dim objContext As MTxAS.ObjectContext
    5: Set objContext = GetObjectContext()
    6: Set objRegister = objContext.CreateInstance(strProgID)
    7: If Not IsMissing(strConnection) Then
    8: DoRegistration = objRegister.SignUp(strXML, strConnection)
    9: Else
    10: DoRegistration = objRegister.SignUp(strXML)
    11: End If
    12: Set objRegister = Nothing
    13: objContext.SetComplete
    14: Set objContext = Nothing
    15: errHandler:
    16: 'Determine if we should write to event log, or raise to the user
    17: DoRegistration = False
    18: objContext.SetAbort
    19: Set objContext = Nothing
    20: Set objRegister = Nothing
    21: Err.Raise Err.Number, Err.Source, Err.Description
    22: End Function

    Line numbers have been added for illustration only, they do not exist in the code. The classfactory has one method with three parameters. strXML is needed to pass along to our IRegister objects. strProgID tells us which IRegister object we need to create. An optional strConnection is a standard database connection string. The DoRegistration method returns a Boolean success or failure flag. To be more purely object oriented, we could return a reference to an IRegister object, and manipulate its properties in ASP.



    Here’s what’s going on. Line 3 declares an object that references our IRegister interface with no implementation. Line 6 points our object’s interface to its IRegister interface. Lines 7-11 make our IRegister calls. We finally do some housekeeping and add some standard error handler code.



    IRegister Components
    Let’s code our components. Here’s a sample.



    Newsletter class


    1: Implements IRegister
    2: Private Function IRegister_SignUp(strXML As String, Optional ByVal _
    strConnection As String) As Boolean
    3: On Error GoTo errHandler
    4: Dim con As ADODB.Connection
    5: Dim cmd As ADODB.Command
    6: Dim objXML As MSXML2.DOMDocument30
    7: Dim strSQL As String
    8: Dim lngReturnedRecs As Long
    9: Set objXML = New MSXML2.DOMDocument30
    10: objXML.loadXML strXML
    11: If objXML.parseError.errorCode <> 0 Then
    12: Err.Raise vbObjectError + 100, , "XML DTD Mismatch"
    13: End If
    14: strSQL = "Insert into Newsletter (name, email) values (?,?)"
    15: Set con = New ADODB.Connection
    16: With con
    17: .CursorLocation = adUseServer
    18: .Open strConnection
    19: End With
    20: With cmd
    21: .ActiveConnection = con
    22: .CommandText = strSQL
    23: .CommandType = adCmdText
    24: .Parameters.Append .CreateParameter("Name", adVarChar,
    adParamInput, 50, objXML.getElementsByTagName("Name").Item(0).xml)
    25: .Parameters.Append .CreateParameter("Email", adVarChar,
    adParamInput, 100, objXML.getElementsByTagName("Email"))
    26: .Execute lngReturnedRecs, , adExecuteNoRecords
    27: End With
    28: IRegister_SignUp = True
    29: Set objXML = Nothing
    30: Set cmd = Nothing
    31: con.Close
    32: Set con = Nothing
    33: errHandler:
    ...
    38: End Function

    Only one method is contained here, our familiar IRegister method. In this example, we read the XML information using DOM and record it in the newsletter table. Following is a portion of our ASP page and XML string that it passes around.



    Client Script
    news.asp page



    1: Set objXMl = Server.CreateObject("MSXML2.DOMDocument")
    2: Set objSignup = Server.CreateObject("Registration.Classfactory")
    3: objxml.loadXML ""
    4: Set root = objXML.documentElement
    5: Set objElement = objxml.createNode(1,"Name","")
    6: objElement.text = Request.Form("Name")
    7: Set currNode = root.insertBefore(objElement,
    root.childNodes.item(1))
    8: Set objElement = objxml.createNode(1,"Email","")
    9: objElement.text = Request.Form("Email")
    10: Set currNode = root.insertBefore(objElement,
    root.childNodes.item(1))
    11: bReturn = objSignup.DoRegistration(objXML.xml,
    _& "Registration.Newsletter", Application("ConnectionString"))
    12: Set objSignup = Nothing
    13: Set objXML = Nothing
    14: Set currNode = Nothing
    15: Set objElement = Nothing