Visual Basic 6 Business Objects
So far, we've looked at how the logical tiers of our application can be deployed across various physical machines. We've also looked at the performance ramifications of using COM and Distributed COM to communicate between our objects.
In this section, we'll go through a number of key concepts that are critical to our business objects and the creation of Visual Basic user-interfaces to our objects. Here are the major themes we'll be considering:
- The UI as a business object client
- Field-level validation
- Object-level validation
- Canceled edits
- Protecting properties and methods
In the sections that follow, we'll be developing a small project to help us discuss these main themes. And in Chapters 5 through 7, where we'll expand upon this discussion, we'll implement a full set of major business objects and a corresponding user-interface that will become the core of our video rental store project.
The UI as a Business Object Client
One of the primary tenants of the CSLA is that the user-interface will rely on our business objects to provide all the business rules and business processing. This implies that there will be a fair amount of communication between our UI-centric business objects and the user-interface itself:
In the CSLA, the UI-centric business objects typically reside on the same machine as the user-interface. In the first section of this chapter, we looked at 2-tier, 3-tier, and Internet physical architectures - so we've seen where the Presentation tier and UI-centric objects may reside.
In a conventional client/server setting (2-tier or 3-tier), we can put these Presentation tier objects and UI-centric objects directly on the client workstations. If we were developing a browser-based user-interface, we'd put these objects on a Web server using an IIS Application.
The following figure shows how all the logical tiers of our application can be deployed across the physical machines in both a 3-tier and Internet scenario:
By keeping the UI-centric business objects as close to the user-interface as possible, we can make the development process as easy as possible for the UI developer. If the UI-centric objects are right there on the client machine then they're easy and safe to work with. This means quick development and a higher quality application.
Most larger projects will be developed in a team setting. Typically, the team will be divided into developers who manage the data, developers who construct the business objects, and developers who develop the user interface (UI) by using the business objects. The people in each of these groups need different skills and a different focus.
The UI developers are those who use the business objects. Ideally, they don't need to understand OO analysis or design; nor do they need to have full knowledge of the complexities of DCOM, network traffic, or implementing inheritance with Visual Basic. Instead, these people should have skills geared toward creating an intuitive user-interface. Their focus is on providing the user with the best possible experience when using the application.
Designing Our Objects to Support the UI
It's our job, as business object designers and builders, to make the UI developer's job as easy as possible. We need to design our business objects so that they are powerful and provide all the features and functionality that the UI developer will need. At the same time, our objects have to be robust and self-protecting.
If an object can be misused, it will be misused. If an object can be created outside of its proper place in an object hierarchy, it will be. In short, if our business objects don't protect themselves then the resulting application will be buggy.
What this really boils down to is that the UI is just a client of the business objects. The business objects are the core of the application, and the UI is secondary. This makes it very easy to change the UI without risking the business logic stored in the business objects.
It also means that we can change our business logic in one place and, by simply upgrading the ActiveX components that contain our business objects, we can change the application's behavior. Often this can be done with little or no impact on the user-interface itself.
We need to make sure that our objects provide sufficient functionality so that we don't limit the capabilities of the UI. At the same time, we need to make sure that our functionality is not tied to any single UI or interface concept. If we compromise our objects for a specific UI then we set a precedence that might mean we'll change our objects any time the UI is changed - and that is exactly what we want to avoid.
Ideally, we should design our UI-centric business objects so they provide a robust and consistent set of services for use by the user-interface. It isn't enough that the objects simply represent real-world entities; they also need to make it easy for the UI developer to create rich and interactive user-interfaces.
Business Behaviors vs. UI Behaviors
The business-related behaviors of each object will vary - depending on the real-world entity that each object represents. At the same time, we should be able to provide a consistent set of behaviors, across all our business objects, to support the user-interface. We don't want the UI developer to have to learn a whole new set of rules to work with each and every business object. Instead, we want all our business objects to basically behave in the same manner.
As we've already seen, our objects provide an interface that is composed of properties, methods, and events that represent real-world objects. This is sufficient to create a simple UI that just lets the user enter information in the hope that it's correct. However, there are a couple other types of interaction that a UI will need if we want to provide more feedback to the user. These include raising errors and having some way to indicate when an object is in a valid state.
We also need to take steps to ensure that the UI developer can't easily break our objects by calling inappropriate methods or setting inappropriate properties. And we need to prevent the UI from creating or accessing objects that need to be protected.
A Basic Object and User-Interface
We've just covered a number of concepts that are very important if we're going to provide a consistent set of behaviors to the users of our objects. To illustrate these concepts, we'll use a simple example. This will let us try out each concept in turn.
The Person Class
For our example, let's create a single class that represents a person. It's going to be easy to work with this class, because we can all understand the properties and behaviors that might make up a Person object. This class also makes a good example for us because there isn't very much difference between a person, a customer, and an employee - and the latter two are both typical business objects that we might need to create.
Defining the Person Object's Interface
We won't get too carried away with the attributes of a person. Certainly we could list hundreds, if not thousands, of attributes, but we'll limit the list to four:
- SSN (social security number)
In Chapters 1 and 3, we discussed events and how they could be used to allow our objects to indicate when certain things happened. In our Person object, we'll implement an event to indicate when the person's age has been changed:
As we'll see, this event will need to be fired any time the BirthDate property is set, since that is when the person will get a new Age property value.
Setting up the Project
If we're going to do some coding, we'll need to set up a project in Visual Basic where we can work. Following the CSLA, we'll actually want to create two different projects: one for our business object (Person), and one for the user-interface.
Putting the UI in a separate project from the business object will help enforce the separation between the presentation and business tiers. The UI itself will be in a program that the user can run, just like any other program we'd normally create. For our business objects, we'll use an ActiveX DLL, since we don't want the overhead of running a whole other EXE for our Person object.
Right now, we're going to concentrate on the Person object. We'll create a project for the UI once we're done with the Person object. So create a new ActiveX DLL project, and change the name of the project to PersonObjects using its Properties window.
Coding the Person Object
Once we've opened our new PersonObjects project, we should see the code window for Class1. Use the Properties window for the class to change the name of the class to Person.
Here is the code for the Person class:
Option Explicit Event NewAge() Private Type PersonProps SSN As String * 11 Name As String * 50 Birthdate As Date End Type Private intAge As Integer Private udtPerson As PersonProps Public Property Let SSN(Value As String) udtPerson.SSN = Value End Property Public Property Get SSN() As String SSN = Trim$(udtPerson.SSN) End Property Public Property Let Name(Value As String) udtPerson.Name = Value End Property Public Property Get Name() As String Name = Trim$(udtPerson.Name) End Property Public Property Let Birthdate(Value As Date) Static intOldAge As Integer udtPerson.Birthdate = Value CalculateAge If intAge <> intOldAge Then intOldAge = intAge RaiseEvent NewAge End If End Property Public Property Get Birthdate() As Date Birthdate = udtPerson.Birthdate End Property Public Property Get Age() As Integer Age = intAge End Property Private Sub CalculateAge() If DatePart("y", udtPerson.Birthdate) > DatePart("y", Now) Then intAge = DateDiff("yyyy", udtPerson.Birthdate, Now) - 1 Else intAge = DateDiff("yyyy", udtPerson.Birthdate, Now) End If End Sub
This class contains a very straightforward set of code. We just accept the values for properties and return them when requested. The exception being that we call the CalculateAge method to recalculate the intAge value each time the Birthdate property is set, so that it can be returned in the read-only Age property.
Also notice that we have code to raise the NewAge event in the Property Let routine for the BirthDate property. When we get a new birth date for the person, we always need to check to see if we've changed the person's age. If we have changed their age, we can raise this event to indicate to our client program that the age is now different.
That's all there is to this class, for the moment. We'll expand on its functionality shortly, but right now we need make sure that we can create a user-interface to work with this simple version.
Page 6 of 13