WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

VB.NET OOP Part 4: Determining Constructors

by Budi Kurniawan, co-author of VB.NET Core Classes in a Nutshell
11/25/2002

We all know that constructors can be used to initialize values. But, did you know that you can use determining constructors to "shape" the objects of a class? In this OOP series article, Budi Kurniawan shows what a determining constructor is and why it is sometimes imperative to have one. Note that in this article, "client" refers to the application that uses your class.

In VB, if you don't write a constructor explicitly in your class, the compiler creates a no-argument constructor for that class. So, basically, an object-oriented (OO) programmer can live without worrying too much about constructors. Many OO programmers concentrate on writing methods and properties in their classes. Many don't realize that constructors can help ensure that the client only instantiates objects based on certain criteria. I call such constructors determining constructors. Basically, a determining constructor is a normal constructor that accepts certain arguments. Having these arguments will ensure that the class instances behave in the way the class designer has intended. In addition, determining constructors can be used for the following purposes:

Related Reading

VB.NET Core Classes in a Nutshell
By Budi Kurniawan, Ted Neward

  1. To ensure that a class is used properly, thus eliminating the possibility of having certain errors.
  2. To prevent the class instances from functioning if the client cannot supply the correct serial number for your software. In other words, to protect your intellectual property.
  3. To prevent an object from being instantiated if the client does not pass the correct arguments.

Making Sure Your Class Is Properly Used

Consider the following class, named Person:


  Public Class Person
    Public age As Integer
    Public name As String
    Public female As Boolean
  End Class

The Person class encapsulates details about a person. The age field stores the person's age, the name field is for the person's name, and female indicates the gender. If female is True, then the Person is female, otherwise the Person is male.

For example, the following code instantiates a Person object and then sets its fields, and retrieves them back:


  Dim bestFriend As New Person()
  bestFriend.age = 25
  bestFriend.female = True

  System.Console.WriteLine("My best friend's name is " &  
    bestFriend.name)
  System.Console.WriteLine(bestFriend.name & " is a " & _
    IIf(bestFriend.female, "woman", "man"))
  System.Console.WriteLine(IIf(bestFriend.female, "She", _
     "He") & " is " & bestFriend.age & " years old")

The result when the program is run is as follows:


My best friend's name is
 is a woman
She is 25 years old

At a glance, you know that the result is not as expected, don't you? Know what causes it? Yes, the programmer forgot to assign a value to the name field of the Person object after the object was instantiated. But that's fine, the error is easily caught. However, consider another scenario. This time, here is the code that instantiates a Person object, sets the field values, and retrieves the values back:


  Dim bestFriend As New Person()
  bestFriend.age = 25
  bestFriend.name = "Alex Simpson"

  System.Console.WriteLine("My best friend's name is " _
                           & bestFriend.name)
  System.Console.WriteLine(bestFriend.name & " is a " & _
    IIf(bestFriend.female, "woman", "man"))
  System.Console.WriteLine(IIf(bestFriend.female, "She", _
    "He") & " is " & bestFriend.age & " years old")

The result is:


My best friend's name is Alex Simpson
Alex Simpson is a man
He is 25 years old

Looks good, doesn't it? But, does it produce the correct result? Is Alex Simpson really a man? Notice that we never set the female value of the Person class, and by default its value is False. Is this because the programmer knew that the default value is False, or is it because he/she forgot to set it? We don't know. This could lead to a serious bug.

Using a determining constructor, you can avoid the two potential problems with the Person class described above. Let's modify our Person class to have a determining constructor.


  Public Class Person
    Public age As Integer
    Public name As String
    Public female As Boolean

    Public Sub New(ByVal name As String, ByVal female As Boolean)
      Me.name = name
      Me.female = female
    End Sub
  End Class

The new Person class has a constructor that accepts two arguments: a String and a Boolean. Now, there is no way the client can instantiate a Person object without passing the person's name and sex. This means, we have eliminated the possibility of having a Person object without a name and without indicating the right gender for that person.

Here is how the programmer will use the Person class now:


  Dim bestFriend As New Person("Alex Simpson", True)
  bestFriend.age = 25

  System.Console.WriteLine("My best friend's name is " & _ 
    bestFriend.name)
  System.Console.WriteLine(bestFriend.name & " is a " & _
    IIf(bestFriend.female, "woman", "man"))
  System.Console.WriteLine(IIf(bestFriend.female, "She", "He") & _
    " is " & bestFriend.age & " years old")

And, here is the result of executing the code:


My best friend's name is Alex Simpson
Alex Simpson is a woman
She is 25 years old

(So, Alex Simpson is a woman!)

Protecting Your Intellectual Property

You have just discovered a quick way to generate very big prime numbers. In computer science and mathematics, prime numbers are a hot topic. It normally takes ages for computers to calculate the next big prime number, but your algorithm has made it very simple and fast. You write this algorithm as a method in your class and it is of course a top secret. This is your hard work and you have spent years on research on this algorithm; therefore, you want to make sure only those who pay can use your class. You do this by requesting the buyer to hand in their public key of the RSA asynchronous cryptography method for you to include in the class. You then re-compile the class and send it to the buyer. The class can only work if the client passes their private key to decrypt a secret field that has been encrypted using their public key. You can use a determining constructor that accepts the private key. Because normally people don't distribute their private key (otherwise the key won't be private anymore), you can rest assured that no one is using your class without paying for it.

Warning: since source files are compiled into intermediate language (IL) code in the .NET Framework, there is always a possibility to decompile it and view the source code.

Forcing the Client to Pass Correct Arguments

In the previous example with the Person class, the class uses a determining constructor to make sure that a Person object always has a name and the correct gender. The determining constructor is as follows.


  Public Sub New(ByVal name As String, ByVal female As Boolean)
    Me.name = name
    Me.female = female
  End Sub

However, this constructor only makes sure that the client passes certain arguments. It does not guarantee that the argument has a correct value. For example, the client can still create a Person object by passing an empty string, or a null, or a string containing spaces only, as the first argument.


Dim bestFriend As New Person(Nothing, True)

Even though it is legal to have a Person object that has a null name, it does not make sense. You should prevent this from happening.

You can do more with determining constructors to enforce certain rules. For example, you can throw an exception from your constructor if you are not happy with the argument the client passes to your class.

The following code is the modified Person class that cannot be instantiated if the name argument to the constructor is null:


Public Class Person
  Public age As Integer
  Public name As String
  Public female As Boolean

  Public Sub New(ByVal name As String, ByVal female As Boolean)
    If name Is Nothing Then
      Throw New Exception("Error! Person does not have a name.")
    Else
      Me.name = name
      Me.female = female
    End If
  End Sub
End Class

If the client passes a null, an Exception is thrown and there won't be a Person whose name is null.

You can do a lot with determining constructors. For example, if you require that the client passes a valid birthday to the person class, you can make sure that the date entered is not later than today.

Budi Kurniawan is a senior J2EE architect and author.


Return to ONDotnet.com