Listing 9.2 CustomerInterface.vb: The ICustomer Interface with Properties Public Interface ICustomer #Region "Properties" 'Define properties for this interface 'that match the table s
Trang 19.1 Define a Class in Visual Basic NET
Before writing code, you should take a moment to decide what data the class needs to contain and what actions a developer (whether it is you or a teammate) would want to perform on that data For the moment, we'll keep it fairly simple by limiting the class to properties representing the columns in the Customers table and to methods that insert, delete, and update data
Technique
Visual Basic NET has a specific kind of code file that you can use to describe the public members of a class: an interface An interface simply lists all the public variables,
methods, and properties that any class implementing that interface must expose
Interfaces are an enormously powerful and flexible feature of object-oriented programs, and this chapter just scratches the surface Because of the fact that an interface has no code, you can focus on the design of your application without the clutter of hundreds of lines of source code
Steps
1 First, create a new Windows Application project and name it CustomerClasses
2 To create a new interface, add a new class to your project by right-clicking on the Solution Explorer window and selecting Add Class Name the new file
CustomerInterface9_1.vb
3 Change the class block declaration so that it reads interface instead of class, and name the class ICustomer You should have a code file like that shown in Listing 9.1
Listing 9.1 CustomerInterface9_1.vb: An Empty Interface
Public Interface ICustomer
End Interface
Add Properties to the Interface
The first items you need to add to your interface are properties to represent the columns
in the Customers table
1 Using the Server Explorer, drill down to the Customers table in the Northwind database so that you have an easy reference to the Customers table
Trang 22 To make your code more readable, add a #Region/#End Region block with the name Properties so that you can expand and collapse your property declarations as needed
3 For each column in the table, add a property declaration to your interface that matches the datatype of the column and its name(see Listing 9.2)
Listing 9.2 CustomerInterface.vb: The ICustomer Interface with Properties
Public Interface ICustomer
#Region "Properties"
'Define properties for this interface
'that match the table structure in name and data type
Property CustomerID() As String
Property CompanyName() As String
Property ContactName() As String
Property ContactTitle() As String
Property Address() As String
Property City() As String
Property Region() As String
Property PostalCode() As String
Property Country() As String
Property Phone() As String
Property Fax() As String
#End Region
End Interface
More About Properties
ICustomer is a simple interface It has only one kind of datatype-a string-and all of the properties are read/write When you begin to write more complex classes, you might need more than just read/write properties Visual Basic NET also has read-only and write-only properties, parameterized properties, and default properties
Read-Only and Write-Only Properties
If you have written classes in Visual Basic 6, you might be scratching your head,
wondering how the code sample in Listing 9.2 declares your properties read/write In Visual Basic 6, all that mattered was whether you wrote the appropriate Property Get and Property Let/Set blocks in your class If you did not have a Public or Friend Property Let/Set, the property was read-only If you did not have a Public or Friend Property Get, the property was write-only
Trang 3In Visual Basic NET, you must explicitly declare a property as read-only or write-only using the ReadOnly and WriteOnly keywords (see Table 9.1)
Table 9.1 Visual Basic NET Property Modifiers Object Purpose
ReadOnly The property cannot be modified outside of the class
WriteOnly The property can only be modified, but only methods that are internal to the
class can read the property
In our example, a developer who is using this class could change the CustomerID
Without the original CustomerID, the class won't be able to find that record in the
database when updating the table, so perhaps you should make the CustomerID property read-only To do this, simply add the ReadOnly keyword to the beginning of the property declaration as in Listing 9.3
Listing 9.3 CustomerInterface9_1.vb: Using the ReadOnly Keyword
'Adding the ReadOnly keyword before the property
'declaration makes the property read-only
ReadOnly Property CustomerID() As String
Parameterized Properties
You can also create properties that accept a parameter For example, in the Northwind database, a customer might have many orders A parameterized property would be a perfect way to access Orders information from the Customer class
A parameterized property (see Listing 9.4) takes one or more parameters that can be used
to qualify the data that the property returns
Listing 9.4 A Parameterized Property
'The nIndex parameter would be used to determine which
'item from a collection of orders should be returned
Property CustomerOrders(ByVal nIndex As Integer) As COrder
Tip
Trang 4One of the advantages to interfaces is the ability to rapidly define all of the classes you plan to use in your application For the previous code example, you could create an interface called IOrder that was similar to the ICustomer interface in Listing 9.2 Instead of returning an actual class from the CustomerOrders property, you could return the IOrder interface The interface would act as a placeholder for any object that implemented the interface This way, you could program the Customer class and put off writing code for the Order class until later
Default Properties
In Visual Basic 6, any property in a class could be defined as the default property for that class For example, if the CustomerID property were declared the default property, both
of the examples in Listing 9.5 would return the customer ID
Listing 9.5 Default Properties in Visual Basic 6
Dim oCustomer As CustomerData
Dim strCustomerID As String
'Example 1: This code places the value of the customer ID property
'into a variable
strCustomerID = oCustomer.CustomerID
'Example 2:This code does the same thing
strCustomerID = oCustomer
In Visual Basic NET, the only kind of property that you can declare as the default
property for a class is a parameterized property
To declare a property as the default property, simply add the Default keyword prior to the property declaration, as shown in Listing 9.6
Listing 9.6 Declaring a Default Property
'Adding the Default keyword before the property declaration
'makes this parameterized property the default property for
'the class
Default Property CustomerOrders(ByVal nIndex As Integer) As COrder
Add Methods to the Interface
Trang 5Now that you have added all the properties you need, you need to add the various
methods that a developer uses to retrieve, insert, update, and delete data from the
Customers table
1 To make your code more readable, add a #Region/#End Region block with the name Methods so that you can expand and collapse your method declarations as needed
2 The point in wrapping a table in a class is to make access to this table as simple as possible You could have one method to insert new rows to the database and one
to update existing rows, leaving the task of determining the state of the object to the code that instantiates it The actions of the class, however, should be as
transparent to other developers as possible To this end, the interface should only define two methods: save and delete (The retrieve method will be defined in a subsequent section.) Add the save and delete methods to your interface, as in Listing 9.7
Listing 9.7 CustomerInterface9_1.vb: Declaring the Delete and Save Methods
#Region "Methods"
'To update or delete a record, a user would have needed to
'retrieve data before modifying any of the properties
Function Save() As Boolean
Function Delete() As Boolean
#End Region
As I mentioned in the introduction to this chapter, one of the great advantages to wrapping up all access to a database table within a class is that you only have to write complex error-handling code once To keep things simple, we are returning a Boolean value from each of these methods, letting other developers know whether the action failed without requiring them to write complex error-handling code
3 Finally, add a ToString method to output all the data of the class in a string This is extraordinarily useful for debugging Your finished interface should look like Listing 9.8
Listing 9.8 CustomerInterface9_1.vb: The Final ICustomer Interface
Public Interface ICustomer
#Region "Properties"
'Define properties for this interface
'that match the table structure in name and data type
ReadOnly Property CustomerID() As String
Trang 6Property CompanyName() As String
Property ContactName() As String
Property ContactTitle() As String
Property Address() As String
Property City() As String
Property Region() As String
Property PostalCode() As String
Property Country() As String
Property Phone() As String
Property Fax() As String
#End Region
#Region "Methods"
'To update record, a user would have needed to
'retrieve data before modifying any of the properties
Function Save() As Boolean
Function Delete() As Boolean
Function ToString() As String
#End Region
End Interface
How It Works
You might have noticed that an interface has no actual code An interface is designed for one purpose: to define a set of public methods and interfaces that are related to a specific entity To put this in object-oriented terminology, an interface represents an abstraction of
an entity-in this case, a customer Interfaces can't function by themselves; a class must implement all of its properties and methods, which is what you will do in the next
sections
Comments
Of course, you don't really need to write an interface before writing the class, and in our current example, it might be overkill The power of an interface really comes into play when you have multiple classes that might implement the same interface in different ways
An interface cannot exist as an object: It has no code and no place to store object data A class that implements an interface has an explicit contract with the interface: The class must implement all the properties and methods of the interface If you declare a variable typed to an interface, that variable could represent any object of any class that
implements the interface
Trang 7You've already seen several examples of interfaces in this book, such as the DataAdapter, DataReader, Connection, Command, and other ADO.NET objects Take, for example, the Command interface At present, two types of Command classes exist: the
OleDbCommand and the SqlCommand Both of these classes implement the
IDbCommand interface The OleDbCommand is responsible for handling data access to any database provider with an OleDB driver, and the SqlCommand connects directly to SQL Server If you wrote a function that processed Command objects-such as a
debugging function that wrote all the properties of a Command to an error log-you might need to handle both kinds Instead of writing two functions, one for each Command type,
Public Sub WriteCommandErrorToLog(ByVal pCommand as SqlCommand)
Public Sub WriteCommandErrorToLog(ByVal pCommand as OleDbCommand)
you could simply declare a function that takes a variable of type IDbCommand, which would accept an instance of either command type:
Public Sub WriteCommandErrorToLog(ByVal pCommand as IDbCommand)
The second solution is far more elegant because, before long, you could end up with Commands for Oracle, Sybase, MySql, SqlAnywhere, DB2, and so on, all of which would implement the IDbCommand interface
It might look like you're missing a few items in ICustomer What method do you call to add new records or retrieve data from the database? If you're working with a new
customer row, how does a developer set the CustomerID? A new type of method called a constructor is executed when a class is instantiated Because constructors can't be
declared in an interface, we will cover this subject in section 9.4