Before you make your test stub available to GUI developers, you should test it yourself. At least, you should create a test form. Let's build one together, one step at a time, to see whether our test stub code works as we expect.
You already have a sketch of your form. Figure 5-9 displayed this form, and for your convenience we repeat it here in Figure 6-14 as your new starting point.
Figure 6-14. Copy of the screen layout from Figure 5-9.
First let's add a command button to get the list of horses and then add an invisible3 ADO data control to hold the recordset your facade object will return. You should also clear the Text property of the txtNamePattern text box and the dlstHorseNames data list control.
The code should declare and create an instance of the facade class. Then it should call that instance's GetHorseList method and move the recordset to the ADO data control. Figure 6-15 displays the result you want in your test form.
Figure 6-15. The facade test stub has returned the names and IDs of two horses.
In the next several paragraphs, we'll show (and talk about) the code you need to achieve the result shown in Figure 6-15.
On a module level, the objFacade variable is declared:
Private objFacade As RaceMaintFacades.fcdHorseMaint |
The facade object is created at the Form_Load event. We use the COM mechanisms (the CreateObject function) rather than the special Visual Basic mechanism (the New keyword) to create the object. If the facade class is eventually installed into an MTS package, using COM mechanisms when creating objects is vital.4
Private Sub Form_Load() Set objFacade = CreateObject("RaceMaintFacades.fcdHorseMaint") End Sub |
The following code reacts when the user clicks the cmdGetHorseList command button:
Private Sub cmdGetHorseList_Click() GetHorseList End Sub |
As always (almost), we refrain from putting procedural code in event procedures. We prefer to set up well-named procedures and call them from the event procedure. In this case, we call the GetHorseList method.
The GetHorseList method is defined as follows:
Private Sub GetHorseList() Set adcHorseList.Recordset = _ objFacade.GetHorseList(txtNamePattern.Text) End Sub |
As you can see, the method calls the facade object's GetHorseList method, sending it the name pattern entered by the user. Then the method saves the recordset returned from the facade into the adcHorseList control. As a result, the form uses its list control to display the names of the two horses we hard-coded into the recordset.
Our next mission is to create the code we need to display more information about one of these horses when the user clicks its name in the list.
The following code reacts to a click in the horse list by calling the GetHorseById method in the form:
Private Sub dlstHorseNames_Click() GetHorseById End Sub |
The GetHorseById code is just as simple as all the other code segments we've created so far:
Private Sub GetHorseById() Dim lngId As Long adcHorseList.Recordset.AbsolutePosition = _ dlstHorseNames.SelectedItem lngId = adcHorseList.Recordset!HorseId Set adcHorse.Recordset = objFacade.GetHorseById(lngId) End Sub |
The first line of code synchronizes the recordset with the list control by making the right record current. Since both the recordset's AbsolutePosition and the list control's SelectedItem properties are 1-based, synchronizing the two is as simple as making the value of Recordset.AbsolutePosition equal to the value of DataList.SelectedItem.
When the right record is current, it's easy to save the ID of the selected horse to the lngId variable.
The next line calls the facade object's GetHorseById method, giving it the ID of the selected horse to work with. Then it saves the recordset returned to the adcHorse ADO data control. Because all the form fields designed to display data about a single horse are bound to the recordset, the form immediately displays data about the horse.
That's all there is to it. Figure 6-16 now displays detailed information about the horse named Nijinsky II.
Figure 6-16. The form now displays test information about one of the greatest racehorses ever.
This information is totally false, but what the heck? It's only there to prove the concept. When we get in touch with the database, will the facade object work? Will it perform all the services needed for the GUI developers to create a good user interface? Those are examples of the questions we should ask now, before we deliver this prototype to GUI developers, allowing them to create a nice user interface prototype to show their customers.
NOTE
Before we do that, just let me (Sten) tell you, that Nijinsky II wasn't bred in the United States at all. He was a male horse, so the h for sex is right, but he was born long before 1988.He was one of the greatest racehorses ever, and I saw him the first time he, as a three-year-old, met older world-class horses. The distance was 2400 meters. At 600 meters from the goalpost, he was dead last.
At this point, I was a bit disappointed—I had expected more from him. Then I heard a voice from a couple of rows up the grandstand saying, "Lester hasn't moved yet!" As my ears heard this, my eyes saw Lester Piggott mildly ask his horse for a move.
One hundred meters later, Nijinsky II had already left all the other great stars far behind him.5
Looking at the form, you can see a need for at least three possible improvements:
Looking in our database, we see that there are only a couple hundred trainers, so we could easily fetch them all. But if the system is likely to be used in a country such as England, France, Japan, or the United States, the number of trainers might be much larger. Perhaps the system should offer users the ability to define a selection of trainers and fetch that selection only.
To support all these scenarios, we should probably make it possible to define a selection but also to define the full set. We'll go on to make these improvements, but that's not the real point here. The important lessons to learn are the following:
As a result of all this work, there's a good chance that users will be happier with what they finally get.
To enhance the facade and the test form, you need to add some code in the facade class as well as in the test form. You must also add or replace some visible objects in the test form. Here goes.
Let's start with the easiest part, adding two ADO data controls to the test form and replacing three text boxes with combo boxes.
That's it. Figure 6-17 shows the enhanced test form in use.
Figure 6-17. The enhanced test form uses different kinds of combo boxes to help the user select information rather than having to type it.
The facade class now needs two new methods: one to create a list of countries and another to create a list of trainers. Both of them resemble the GetHorseList method more than a little—or at least they will as long as they contain only test stub code. The method that composes a list of countries is the easier one to create because it doesn't accept any arguments. Since the number of countries always will be manageable, the GetCountryList method returns them all.
Our test stub code for these methods looks like this:
Public Function GetCountryList() As Recordset Dim rs As ADOR.Recordset Set rs = CreateObject("ADOR.Recordset") rs.Fields.Append "CountryCode", adVarChar, 3 rs.Fields.Append "Country", adVarChar, 20 rs.Open rs.AddNew rs!CountryCode = "USA" rs!Country = "USA" rs.AddNew rs!CountryCode = "GB" rs!Country = "Great Britain" rs.AddNew rs!CountryCode = "SWE" rs!Country = "Sweden" Set GetCountryList = rs End Function |
There's nothing to explain in this code. It just returns a list of countries, each country represented by a country code and a country name. To make things more interesting when running the test form, we took the opportunity to change the GetHorseById method just a little bit. We made the code appoint a different BredIn country to each of the two horses. Here's that little code snippet only:
Case 10 rs!HorseName = "Nijinsky II" rs!BredIn = "GB" rs!Trainer = 16 Case 20 rs!HorseName = "Nearco" rs!BredIn = "USA" rs!Trainer = 20 |
The GetTrainerList function is almost the same as the GetCountryList method. As you would expect, it returns different fields—trainers instead of countries—and it takes an optional argument we don't pay any attention to in the test code. Even though the GetTrainerList method is different in these respects, its structure and its behavior are almost the same:
Public Function GetTrainerList _ (Optional ByVal strLastNamePattern As String) As Recordset Dim rs As ADOR.Recordset Set rs = CreateObject("ADOR.Recordset") rs.Fields.Append "TrainerId", adInteger, 4 rs.Fields.Append "TrainerName", adVarChar, 40 rs.Open rs.AddNew rs!TrainerId = 16 rs!TrainerName = "Kahn, Michael" rs.AddNew rs!TrainerId = 20 rs!TrainerName = "Gustafsson, Tommy" Set GetTrainerList = rs End Function |
We need to add code to the test form to call a method that fetches and displays trainers in the proper combo box. We also need a method to fetch and display countries in another combo box:
Private Sub Form_Load() Set objFacade = CreateObject("RaceMaintFacades.fcdHorseMaint") GetTrainerList GetCountryList End Sub |
We also have to implement both of these methods, which as you can see from the following code snippets is extremely easy. First the GetTrainerList method:
Private Sub GetTrainerList() Set adcTrainerList.Recordset = objFacade.GetTrainerList() End Sub |
Now the GetCountryList method:
Private Sub GetCountryList() Set adcCountries.Recordset = objFacade.GetCountryList() End Sub |
And that's it! You can now consider your facade object good enough to deliver to the GUI developers. They can make good use of it. Perhaps they will even suggest some early improvements.
Of course, you should also include mechanisms in your test form to test the Save, Delete, and GetEmpty methods. We won't, however, bother with that now. Instead we'll see what the GUI developers can do with the facade class we give them. We'll do that in the next chapter.
Before we go on to do that, let's just briefly mention XML in connection with these early prototypes.
This chapter assumes that you're using ADO recordsets rather than XML documents to transport your data. If you used XML, the main difference from the procedures we followed in this chapter would be that functions now returning ADO recordsets would return string variables containing XML text. Also, method call arguments now specifying ADO recordsets would change into such string variables.
We talk specifically about XML in Chapters 20 and 21, but you should understand that nearly all the text and graphics of this chapter will remain valid for you even if you're going to use XML.