Building an Employee Factory in VB.NET

Usually, when you want to create a new object, you just use VB's trusty New keyword along with the class you want to instantiate, as follows:

Dim Emp As Employee
Emp = New Employee()

However, the client application taking such direct control of the instantiation process sometimes isn't the best approach. For example, suppose an application accepts user input and uses it to create a new employee object. The only tricky thing is that there are a few different kinds of employees, represented by a few different kinds of classes:

  • The SalariedEmployee contains a Salary property.
  • The HourlyEmployee class contains a HourlyRate property.
  • The Contractor class contains a BillingRate property.

Each of these classes inherits from Employee, which has properties and methods common to all employees, such as the employee's first and last names, his or her SSN, and so forth.

The form where the user enters his or her information is simple: It accepts first name, last name, SSN, and employee type. (None of the more specific information is collected on this form.) It also contains a dropdown listbox that asks which type of employee to create. The dropdown list retrieves its options from a database, but you can bet it includes Salaried Employee, Hourly Employee, and Contractor.

The user enters the new employee information, selects an employee type, and clicks the Add New Employee button on the form. What happens? Probably something like this:

Dim newEmp As Employee
If empTypeCombo.SelectedItem.ToString() = "Salaried Employee" Then
   newEmp = new SalariedEmployee()
ElseIf empTypeCombo.SelectedItem.ToString() = "Hourly Employee" Then
   newEmp = new HourlyEmployee()
Else
   newEmp = new Contractor()
End If
newEmp.FirstName = firstName.Text
newEmp.LastName = lastName.Text
...

This code is pretty straightforward, but it ties itself to the Employee class a little too tightly—what object-oriented folks would refer to as coupled. To understand this issue better, imagine that a new employee type is added—say, Intern. The following would need to be updated:

  • The Intern class has to be written and inherited from Employee, just like all the rest of the classes.
  • The database (where the dropdown listbox retrieves its options) has to be updated.
  • The code in the form under the button click event (listed above) has to be modified.

There's no avoiding the first two, but the last one has big implications because other applications probably work with employees as well. So, you'd have to revisit any application that uses the Employee class (or one of its descendants) to see whether it needs to be updated because of this change.

This is what coupling means: Two classes are so tightly bound that a change in one necessitates a change in the other. Although no class can be completely decoupled from all other classes (they have to work together and communicate somehow!), it is good object-oriented programming practice to reduce these dependencies as much as possible.

In this example, if you can strike that third bullet point and make it so that an added employee type requires only the recompiling of the employee classes, you are in much better shape for maintenance down the road. But how do you do that? Obviously, at some point you've got to verify what type of employee the user wants to create and instantiate it, right? Right! But, if you can move that code into the Employee class itself (where you're already making a change), the impact can be minimized and the form is decoupled from the class!

The Factory Factor

Probably the best way to work this solution is by implementing a simple factory. A factory, in object-oriented parlance, is a way to take control of the instantiation of an object. Factories come in all shapes and sizes. In some systems, all classes have corresponding factory classes that handle all the instantiations of their corresponding classes. To keep this example simple, the factory will be no more than a shared method added to the Employee class:

Public Class Employee
   Public Shared Function CreateEmployee(ByVal empType As String) _
      As Employee
      Dim newEmp As Employee
      If empType = "Salaried Employee" Then
         newEmp = New SalariedEmployee()
      ElseIf empType = "Hourly Employee" Then
         newEmp = New HourlyEmployee()
      Else
         newEmp = New Contractor()
      End If
      Return newEmp
   End Function
   ...
End Class

Look familiar? The code has essentially just been moved from the form to the Employee class. Why? Because that's where it belongs! Now, a change, such as the addition of a new employee type, is much less likely to impact the client code.

An important point to remember is the function must be shared. This allows the client to call the function on the class itself, before the object is instantiated. Obviously, that's important because instantiating the object is exactly what this function does!

The form's button click event is pretty simple now:

Dim newEmp as Employee
newEmp = Employee.CreateEmployee(empTypeCombo.SelectedItem.ToString())
newEmp.FirstName = firstName.Text
newEmp.LastName = lastName.Text
...

No New! All the dirty instantiation details are left to the CreateEmployee factory function.

And now, to add the Intern class, you just have to:

  • Write the Intern class and inherit from Employee, just like all the rest of the classes.
  • While you're modifying the file with the Employee classes in it, update the CreateEmployee factory function to add another conditional.
  • Update the database (where the dropdown listbox retrieves its options).

The Employee classes are recompiled, but all the client code is good to go.

Protect Your Class

One more detail to consider is that this solution does not stop a client application from instantiating an Employee class using the New keyword. It simply provides another, better option. If you want to stop any users from directly instantiating your class, the simple way to do that is this:

Public Class Employee
   Protected Sub New()
   End Sub
   ...

If you don't specify a constructor for your class, the .NET Framework creates one automatically for you. So, what's the point of creating an empty constructor? The default constructor is Public, which enables anyone to instantiate the class by using the New keyword. The above code uses the Protected constructor instead.

Typically for methods and variables, Protected indicates that no one outside the given class can access the method/variable. And that's what it is doing here, too. But, you don't call the constructor directly. It gets called when you instantiate the class. So, if you make the constructor for a class Protected, no code outside your class can instantiate it! Of course, your CreateEmployee is okay because it is a method of this class. However, if you write code like this in the form button's click event:

Dim newEmp = New Employee

You'll get this error:

'Employee.Protected Sub New()' is not accessible in this context
because it is 'Protected'.

By making the constructor Protected, you now force anyone using this class to call your factory method—there's no other way to instantiate the class!

About the Author

Bill Hatfield is the bestselling author of half a dozen books on software development, including ASP.NET 2 For Dummies. He works as a Course Developer for programming courses at Avanade (in Seattle), but is fortunate enough to work from his home in Indianapolis. That way he gets the benefits of high tech work AND snow.



About the Author

Bill Hatfield

Bill Hatfield is the best-selling author of numerous books for developers, including ASP.NET For Dummies, Active Server Pages For Dummies (on Classic ASP) and Visual InterDev For Dummies. He is also the editor of Visual Studio .NET Developer, a monthly technical journal from Pinnacle. He's an experienced corporate trainer and works in Indianapolis, IN where he also co-founded the local .NET group, the Indianapolis .NET Developers Association.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Not long ago, security was viewed as one of the biggest obstacles to widespread adoption of cloud-based deployments for enterprise software solutions. However, the combination of advancing technology and an increasing variety of threats that companies must guard against is rapidly turning the tide. Cloud vendors typically offer a much higher level of data center and virtual system security than most organizations can or will build out on their own. Read this white paper to learn the five ways that cloud …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds