Building Mobile Business Objects
Building Mobile Business Objects
Overview
The drive to connect people, process and devices is a never ending cycle of development. Enterprises are demanding applications that deliver seamless communication with their partners and customers without sacrificing security, transactions, reliability and performance. Distributed application systems are quickly becoming the norm. Service orientation is an approach to software design and development that helps to solve this problem.
Service oriented (SO) design defines message oriented programs called services that are the fundamental solution building blocks. Service oriented architecture results in loosely coupled application systems that enable business to respond faster to change. SOA allows for a more natural depiction of the business process, real life events and system boundaries in software, improving the ability to respond to changes in the business. Also, the closer modeling of application systems to reality allows for relevant and actionable business data and loose coupling between services that reduce the ripple effect of changes.
The ever increasing complexity of enterprise systems has tested the limits of the OO architecture and design and paved the way for the evolution of SOA. Service orientation is a compliment to object orientation not a replacement. The primary distinction between SO and OO is in how you view applications. In a solely object oriented approach, an application is a tightly coupled program built from class libraries that have dependencies on each other. An SO based application is a different entity entirely, composed of loosely coupled autonomous services programs. SOA defines the message oriented services to build distributed solutions, created with object orientation.
It’s the combination of OO and Service oriented that are important to understand when building not only mobile applications but any type of .NET application. In this article we will look at how these types of objects are built and the ways they can be used within mobile applications using Visual Studio 2005.
Introduction to mobile business objects
Object oriented principles were developed to solve the problems of modern day programming. As shown in Table 1, OO is based on a set of design principles that define behaviors that are common to objects. By definition an object is a set of software that contains properties, variables and methods that describe something. For example, objects are used to describe a customer, invoice or a purchase order. Business objects are built using these same core principles with differences in architecture and methodology to overcome the shortcomings of OO within a distributed architecture.
Table 1: Principles of Object Oriented Development
OO Concept |
Definition |
Abstraction |
Implementation of code to mimic actions and characteristics of any real world entity |
Encapsulation |
Defines that a group of related properties, methods, and other members are treated as a single unit or object. Encapsulation also makes it easier to change the implementation at a latter date by hiding the object specifics. |
Polymorphism |
Defines that you can have multiple classes that can be used interchangeably, even though each class implements the same properties or methods in different ways. Polymorphism is essential to object-oriented programming because it allows the use of items with the same names, no matter what type of object is in use at the moment. |
Inheritance |
Defines the ability to create new classes based on an existing class. The new class inherits all the properties and methods and events of the base class, and can be customized with additional properties and methods. |
For example, one of the most common OO design problems in a distributed system is that objects become chatty. A chatty system is one where there is a lot of unnecessary communication between the client and the services. This often occurs because clients have to call multiple methods for each action they need to perform. This leads to excessive network load. Given that mobile devices already have resource limitations this can lead to a poorly scaled application and poor end user experience.
By definition business objects are encapsulated units of information and methods that relate to business data or functionality. Fundamentally, they are about separating the logic from the database and allowing developers to build self contained units of business logic. Technically, business objects may operate independently or encapsulate lower level OO based objects that implement a business process.
Figure 1 A logical application architecture
Using business objects as the base of your application requires a shift in thinking about application architecture. Traditional applications are considered an autonomous entity that is composed of layers and then deployed into tiers. However, business objects have changed this paradigm to a service model that is based on message based interaction where services are considered actors and data is passive. This allows for a separation between different layers of the application and leads to a logical architecture as shown in Figure 1. In this model objects become smart data containers.
Figure 2 The basic property declaration
An Object is a structure containing data and methods that manipulate data. A class is the simplest example of an object. By definition a class is a blueprint that defines variables, properties and methods common to objects of a certain kind. A class is considered an abstract representation where an object is a useable example of the thing that the class represents. Properties are part of the program interface and describe the characteristics of a class. Properties hold information about a class when loaded into memory. The body of the property declaration contains Get and Set properties that describe the object as shown in Figure 2. The actual value of the property is stored outside of the property in variables and is accessed externally through the Get and Set properties.
Objects are often data centric in distributed systems. A data centric object is designed to treat data as passive. Good development practice means that you don’t necessarily map exactly to what is in the database. This creates a level of abstraction. The object provides a transport for data and contains no behavior. These simple business objects contain one or more simple attributes and a list of supported verbs. For example, Listing 1 shows an example of a data centric customer class.
Listing 1: A data centric customer class.
Public Class clsCustomer
Private _Cust_Address As String
Private _Cust_Name As String
Private _Cust_ID As String
Private _Cust_Phone As String
Private _Cust_State As String
Private _Cust_Zip As String
Private _Cust_City As String
Public Sub New(ByVal Cust_address As String, ByVal Custname As String, ByVal Cust_ID As String, ByVal cust_phone As String, ByVal Cust_state As String, ByVal Cust_zip As String, ByVal Cust_city As String)
Me.Cust_Address = Cust_address
Me.Cust_Name = Cust_Name
Me.Cust_ID = Cust_ID
Me.Cust_Phone = cust_phone
Me.Cust_State = _Cust_State
Me.Cust_zip = _Cust_Zip
Me.Cust_City = _Cust_City
End Sub
Public Property Cust_Address() As String
Get
Return _Cust_Address
End Get
Set(ByVal value As String)
_Cust_Address = value
End Set
End Property
Public Property Cust_Name() As String
Get
Return _Cust_Name
End Get
Set(ByVal value As String)
_Cust_Name = value
End Set
End Property
Public Property Cust_ID() As String
Get
Return _Cust_ID
End Get
Set(ByVal value As String)
_Cust_Name = value
End Set
End Property
Public Property Cust_Phone() As String
Get
Return _Cust_Phone
End Get
Set(ByVal value As String)
_Cust_Phone = value
End Set
End Property
Public Property Cust_City() As String
Get
Return _Cust_City
End Get
Set(ByVal value As String)
_Cust_City = value
End Set
End Property
Public Property Cust_State() As String
Get
Return _Cust_State
End Get
Set(ByVal value As String)
_Cust_State = value
End Set
End Property
Public Property Cust_zip() As String
Get
Return _Cust_Zip
End Get
Set(ByVal value As String)
_Cust_Zip = value
End Set
End Property
End Class
This type of business object is designed to encapsulate the data definition of a business object. For example, when describing a customer this would include the customer name and address information. Each defined property represents a value that describes an spect of the customer. All the properties contain simple attributes that represent a value for the object such as a string or integer. This object is instantiated and a customer is added using the code in listing 2.
Listing 2:Adding a customer to the object.
Dim Customer As New clsCustomer(Cust_Address:="123 Anywhere St.", _
Custname:="Mondo Corp Inc.", _
Cust_id:="Q1234", _
Cust_phone:="6033452345", _
Cust_State:="New Hampshire", _
Cust_zip:="03110", _
Cust_city:="New Hampshire")
Figure 3 Adding Methods to a class
Object may also contain behaviors. This enables objects the ability to perform actions.
These are implemented by Methods exposed by a class in either a function or sub. Both are responsible for executing code on behalf of the calling application. However, the sub procedure does not return a value while the function does. For example, we can add the following two methods as shown in Figure 3.
The Array Class
Found in the System namespace, the array is one of the basic types of system classes. By default arrays are declared as a fixed size. This means that the total number of items they can contain is declared during initialization. Listing 3 shows how to declare an array based on the customer class and then add two entries.
Listing 3: Declaring and adding two customers to the array.
Dim customers(1) As clsCustomer
customers(0) = New clsCustomer("123 Anywhere St.", "Alfred Industries", "ALFRE", "123-456-7890", "NH", "03110", "Bedford")
customers(1) = New clsCustomer("456 Main St.", "General Industries", "GENERAL", "123-764320", "NH", "03110", "Bedford")
Figure 4 Arrays are strongly typed
When combined with a class object, arrays are considered strongly typed as shown in Figure 4. This means that they can only contain objects of a specific type. For example the following code shows how to set the first customer name.
customers(0).Cust_Name = "Alfred Industries"
Arrays are an ideal solution for transporting data when you know ahead of time how many items are contained. Arrays are often used when passing a number of similar objects to a method or function call as a parameter. Listing 4 shows an example of how the customer array can be passed to another function and then accessed.
Listing 4: Passing an array structure
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim customers(1) As clsCustomer
customers(0) = New clsCustomer("123 Anywhere St.", "Alfred Industries", "ALFRE", "123-456-7890", "NH", "03110", "Bedford")
customers(1) = New clsCustomer("456 Main St.", "General Industries", "GENERAL", "123-764320", "NH", "03110", "Bedford")
Call ReceiveArray(customers)
End Sub
Private Function ReceiveArray(ByVal CustArray As Array)
' get the size of the array and subtract one
' as arrays always start with zero
Dim receiveSize As Integer = (CustArray.Length - 1)
' instantiate the array with customer information
Dim customers(receiveSize) As clsCustomer
CustArray.CopyTo(customers, 0)
' iterate through the customer names
Dim i As Integer
For i = 0 To (customers.Length - 1)
MsgBox(customers(i).Cust_Name)
Next
End Function
Defining Interfaces
The greatest percentage of development time is spent on the business specific parts of an application. This makes business rules and objects the heart of most applications. Also, this makes these groups of objects an ideal unit of reuse. Business components are encapsulated in two directions. The external world must not know anything about component internals. Internally the object must not know anything about external components other than allowing interested objects to register for notification of specific events or exception conditions.
Figure 5 Adding an interface to a project
Given these requirements distributed objects are not architected as traditional objects. Rather they have a few course grained methods and carry no client specific state. These are the same design considerations for architecting Web Services, which is the primary reason why Web services and distributed objects are so similar. There are more similarities between the two. For example, each Web services specify a contract, described by WSDL. Distributed objects also specify a contract which is their interface defined in some form of an Interface Definition Language (IDL). Both also face similar complexities surrounding security, identity, concurrency and transaction management. Visual Studio provides the Interface file as shown in Figure 5.
Interfaces like classes define a set of properties, methods and events. But unlike classes, interfaces do not provide an actual implementation. They are implemented by classes and defined as separate entities from the class. Interfaces define a contract that requires any class to implement the entire definition. Listing 5 shows the interface file for the customer class.
Listing 5: The customer interface file
Public Interface ICustomer
Sub AddCustomer()
Function GetCustomerBalance() As Integer
Property Customer_Name()
Property Customer_ID()
Property Customer_Address()
Property Customer_City()
Property Customer_State()
Property Customer_ZipCode()
Property Customer_Phone()
End Interface
Figure 6 Implementing the customer interface
Interfaces define features as small groups of closely related members. This allows the creation of enhanced implementation for interfaces without jeopardizing existing code. Also, this minimizes the possible version compatibility problems. Additional features can be added by implementing additional interfaces as shown in Figure 6.
Although the classes that implement an interface are able to evolve, the actual interfaces themselves cannot. Any changes to a published interface may break existing code. Like a contract, both the implementing class and the interface have a role to play. The publisher of an interface agrees to never change the interface and the implementer agrees to implement the interface as it was designed.
Introducing Collections
Business objects have both structure and definition. A collection is an object that allows the grouping of other objects. It is a set of similarly typed objects grouped together. The .NET Compact Framework contains a variety of built in collection types that can be found in the System.Collections namespace as shown in Table 2.
Table 2: The System.Collection Namespace
System.Collections |
Provides interfaces and classes that define various collections of objects |
System.Collection.Specialized |
Contains specialized and strongly typed collections. |
System.Collections.Generic |
Contains specialized interfaces and classes that define generic collections |
This namespace contains interfaces and classes that define various types of pre-built collections. These system defined collections are useful for storing heterogeneous data. Depending on the type of collection they may be either strongly or weakly typed. However, when using a strongly typed class the type of the item is known and doesn’t require any additional conversion. Listing 6 shows an order class that will be used to demonstrate the various types of collections.
Listing 6: An example of an order class
Public Class Order
Private _OrderDate As Date
Private _OrderNumber As Integer
Private _OrderAmount As Decimal
Private _CustomerName As String
Public Sub New(ByVal orderdate As Date, ByVal ordernumber As Integer, ByVal orderamount As Decimal, ByVal customername As String)
Me.OrderDate = orderdate
Me.OrderNumber = ordernumber
Me.OrderAmount = orderamount
Me.CustomerName = customername
End Sub
Public Property CustomerName() As String
Get
Return _CustomerName
End Get
Set(ByVal value As String)
_CustomerName = value
End Set
End Property
Public Property OrderAmount() As Decimal
Get
Return _OrderAmount
End Get
Set(ByVal value As Decimal)
_OrderAmount = value
End Set
End Property
Public Property OrderDate() As Date
Get
Return _OrderDate
End Get
Set(ByVal value As Date)
_OrderDate = value
End Set
End Property
Public Property OrderNumber() As Decimal
Get
Return _OrderNumber
End Get
Set(ByVal value As Decimal)
_OrderNumber = value
End Set
End Property
End Class
System.Collections Namespace
Closely related data can be handled more efficiently when grouped together into a common collection. Instead of writing separate code to handle each individual object, you can use the same code to process all the elements of a collection. Managing a collection is done with a combination of the array class and the System.Collections classes. This combination is used to add, remove, and modify individual elements of the collection or a range of elements. By default memory management is handled automatically and the capacity of a collection is expanded as required. Additionally collections provide thread safety when accessing member of the collections. Collections also generate an enumerator that makes it easy to iterate through individual elements.
The .NET Framework Base Class Library offers a formal definition of a collection as defined by the System.Collections.ICollection interface. All of the types in the System.Collections namespace implement the ICollections interface. Table 3 shows the methods that are made available when implementing this interface.
Table 3: The ICollection interface features
Name |
Description |
CopyTo |
This method allows the user of the collection to obtain an array of the collection's items. This is useful since it is typically easier to manipulate an array of items versus using an enumerator. |
Count |
This read-only property returns the number of items currently in the collection |
IsSynchronized |
This read-only property returns true if the collection type has been designed to be thread safe. If you are using a single collection object from multiple threads, and this property is false, then you must add the code to synchronize operations on this object. |
SyncRoot |
This read-only property returns the object, which can be used to manually synchronize the collection. |
These built in collections include the ArrayList and HashTable collections, along with the CollectionBase class which enables the extension of strongly typed collections. This namespace also contains a variety of pre-built collections as shown in Table 4. These include the Stack and Queue which are essentially an ArrayList underneath the covers, but also places restrictions on the order that elements can be accessed from the collections. There’s also a BitArray class for effectiently storing a collection of Boolean values.
Table 4: Collections of the System.Collections namespace.
Collection Type |
Description |
ArrayList |
Used to manage an array whose size is dynamically increased as required |
BitArray |
Used to manage a compact array of bit values which are represented as Booleans |
HashTable |
Represents a collection of key/value pairs that are organized based on the hash code of the key |
Queue |
Represents a first in, first out collection of objects |
Stack |
Represents a simple last in, first out collection of objects. |
SortedList |
Represents a collection of key/value pairs that are sorted by the keys and are accessible by key and by index. |
The ArrayList
The ArrayList collection is similar to the standard array class. The major difference is that the Array List is not strongly typed and the Arraylist size can be changed dynamically. For example Listing 7 shows how to instantiate an ArrayList and add two order objects.
Listing 7: Creating an ArrayList collection.
Dim orders As ArrayList = New ArrayList
orders.Add(New Order("1/1/2006", "1234", 1200.54, "ALFKI"))
orders.Add(New Order("1/31/2006", "4567", 1895.54, "CAPI"))
When accessing an item in the collection there is no available IntelliSense. This is because the ArrayList is weakly typed. In order to use the arraylist and access items with intellisense requires an object cast as shown below.
ctype(orders(0), Order).CustomerName = "ALFKI"
Figure 7 IntelliSense on the cast object.
Once the cast is complete IntelliSense becomes available as shown in Figure 7. Also, collection enumeration is available as shown in Listing 8.
Listing 8: Enumerating an ArrayList
Dim i As Integer
For i = 0 To (orders.Count - 1)
MsgBox(CType(orders(i), Order).CustomerName)
Next
The major advantage of the ArrayList is that you do not need to know in advance how many items it will contain. One of the more important methods of the ArrayList is the ToArray function. This function is used to copy collection items to an array. When called use the type of item you want in the array as a parameter. Listing 9 shows how to place orders into the ArrayList and then copy them into an array.
Listing 9: Copying order items to an array
Dim orders As ArrayList = New ArrayList
orders.Add(New Order("1/1/2006", "1234", 1200.54, "ALFKI"))
orders.Add(New Order("1/31/2006", "4567", 1895.54, "CAPI"))
Dim orderarray() = orders.ToArray(GetType(Order))
Dim OrderArray() = orders.ToArray(GetType(Order))
HashTable Class
The HashTable class provides a weakly typed collection of key-value pairs. The HashTable is designed to retrieve items key. Each HashTable object consists of buckets that contain the individual elements of the collection. A bucket is a virtual subgroup of elements within the collection that is used for searching and retrieving the data elements. Each bucket is associated with a hash code, generated using a hash function based on the key element.
When an object is added to a Hashtable it is stored in a bucket that is associated with the hash code that matches the object’s hash code. When a value is being searched for in the Hashtable the hash code is generated for that value and the bucket associated with that hash code is searched. Listing 10 shows an example of how to add orders to a Hashtable.
Listing 10: Adding orders to a HashTable
Dim orders As New Hashtable
orders.Add("AlFKI", New Order("1/1/2006", 1234, 1200.54, "ALFKI"))
orders.Add("CAPI", New Order("1/31/2006", 4567, 1954.12, "CAPI"))
As each item is added to the collection the customer name is used as the key. This value is used to calculate the hash. The hash function is an algorithm that returns a numeric hash code based on a key. By default the hash function always return the same code for the same key. The hash is a numeric value that is used to uniquely identify an item’s key. The actual key is not stored in the collection only it’s hash value. To set the value of an item within the collection a combination of the key and casting is used as shown below
CType(orders("ALFKI"), Order).CustomerName = "ALFKI"
The key can also be used to quickly locate items contained in the collection. Listing 11 shows an example of how this can be done.
Listing 11: Locating a key within the collection
If orders.ContainsKey("CAPI") Then
txtbox.text = "Value found"
End If
Queue Class
The Queue class functions like a line of people of waiting to purchase concert tickets. When the ticket window opens the first person is sold their tickets and each person is served in the order they are in line. The Queue class creates a weakly typed collection that orders items as they are added. This type of service mechanism is called First in First Out (FIFO).
Internally, the queue class maintains an array of objects and two integers that mark the beginning and ending positions. When an item is added to the queue the internal capacity is checked to determine whether the array has enough room to store the new item. If it doesn’t the size of the array is automatically increased. New items are added at the position specified by the ending integer. As each item is added this integer is then incremented. The Queue class exposes an Enqueue method to add new items to the collection. For example, Listing 12 shows how to add two order items to a Queue class.
Listing 12: Adding order items to the Queue class
Dim orders As New Queue
orders.Enqueue(New Order("1/1/2006", 1234, 1200.54, "ALFKI"))
orders.Enqueue(New Order("1/31/2006", 4567, 1954.12, "CAPI"))
By default, the Queue class provides no index, items are accessed by the order they are added. The Dequeue method accesses and removes order items from the queue. The following code shows how to retrieve the first entered order item.
Dim firstOrder As Order = orders.Dequeue
***Insert Note***
The next call of the Dequeue method will retrieve the second item.
The Peek method provides a way to review items without removing them from the collection. For example, the following code will access the first item but not remove it from the collection.
Dim firstOrder As Order = orders.Peek
The use of the queue class is limited to specific business situations that require this type of behavior. For example, where you need to access messages and processes them in the order they arrive.
Stack Class
Opposite of the queue is the Stack class. This stack class creates a weakly typed collection where the last item added to the stack is returned first. Like a stack of papers on your desk, the top paper in the stack is the last one added. This type of service mechanism is called Last in First Out (LIFO). The stack class exposes the push method to add new items to the collection. Listing 13 shows an example of adding two order items to the Stack class.
Listing 13: Adding order items to the Stack class.
Dim orders As New Stack
orders.Push(New Order("1/1/2006", 1234, 1200.54, "ALFKI"))
orders.Push(New Order("1/31/2006", 4567, 1954.12, "CAPI"))
Like the Queue class items in the Stack can’t be accessed directly. The last added item is accessed in the stack class by using either the Push or the Pop method. The Pop method retrieves and then removes the item from the collection as shown below.
Dim FirstOrder As Order = orders.Pop
The Peek method is used to retrieve the item but doesn’t remove it from the stack as shown below.
Dim Secondorder As Order = orders.Peek
Like the queue, stack objects are only used in specific business situation that require their special behavior.
SortedList Class
The SortedList class combines the features of both the array and hashtable. By default, it exposes class items by index and unique key. The SortedList class maintains two arrays, one for keys and the other for values. The value array is used when a value is requested by index, like an array. When a value is requested by key, the index is obtained by searching the key array. Once the proper key is found then the matching value is obtained from the value array, which behaves like a HashTable with additional operations. Listing 14 creates a new SortedList collection and adds two order items to it.
Listing 14: Creating a sorted list with two order items
Dim orders As New SortedList
orders.Add("AlFKI", New Order("1/1/2006", 1234, 1200.54, "ALFKI"))
orders.Add("CAPI", New Order("1/31/2006", 4567, 1954.12, "CAPI"))
As a new item is added, the key array is re-sorted and the value array is adjusted to reflect the changes. In general requesting values by key is slower with a SortedList than a HashTable. However, the advantage of being able to request a value by index makes this valuable in certain business situations. Listing 15 shows an example of retrieving data using either the index or key.
Listing 15: Retrieving data from the SortedList collection
Dim orderALFKI As Order = orders("ALFKI")
Dim OrderSecond As Order = orders.GetByIndex(1)
When retrieving data the GetKey(index) method as shown below is used to retrieve an item specified by the key.
txtMessage.Text = "The key for this is " & orders.GetKey(0)
The other way around is the IndexOfkey(key) method. This method retrieves the index of the specified key as shown in the following.
txtMessage.Text = "The index for this is " & orders.IndexOfKey("CAPI")
This collection is useful for business situations where item access is based on either the key or the index. However, be aware that these additional features come with a performance penalty. If the business requirements specify a simple key-value pair and no need for an item index then a HashTable would make the better choice.
Implementing Custom Collections
Not all business data fits neatly into the set of built in system collections. Custom collection classes provide a strongly typed business object that defines the underlying data while abstracting out the ADO.NET and XML programming models. This is particularly effective in large systems when an architect designs a data access layer that contains custom business classes and then distributes the assemblies to other developers within the organization. Custom collections start with a business definition class that describes the entity. For example, listing 16 contains a class that provides an entity definition of a book.
Listing 16: The book collection
Public Class Book
Private _Author As String
Private _Title As String
Private _ISBN As String
Public Sub New(ByVal Author As String, ByVal Title As String, ByVal ISBN As String)
_Author = Author
_Title = Title
_ISBN = ISBN
End Sub
Public Property ISBN() As String
Get
Return _ISBN
End Get
Set(ByVal value As String)
_ISBN = value
End Set
End Property
Public Property Title() As String
Get
Return _Title
End Get
Set(ByVal value As String)
_Title = value
End Set
End Property
Public Property Author() As String
Get
Return _Author
End Get
Set(ByVal value As String)
_Author = value
End Set
End Property
End Class
***Insert Note***
Custom Collections are actually made up of two separate class files.
Custom collections are based on inheritance from the CollectionBase, ReadCollectionBase or DictionaryBase class. For example, the .NET framework uses the CollectionBase as the base class for a large portion of the built in strongly typed classes. Listing 17 contains the shell code for implementing a strongly typed books collection.
Listing 17: The shell of a strongly typed books collection
Public Class books
Inherits CollectionBase
End Class
***Insert Note***
A common naming convention is to provide a plural name for the collection based on the name of the object that is being stored. In this example this means that the collection named books will contain an object of book.
The CollectionBase contains an InnerList and List property that represent the internally stored collection of data. This property is accessed by implementing a Default Property indexer that returns a strongly typed object. Listing 18 contains the updated Books class.
Listing 18: Adding a default indexed property to the strongly typed collection.
Public Class books
Inherits CollectionBase
Default Public Property Item(ByVal Index As Integer) As Book
Get
Return CType(List.Item(Index), Book)
End Get
Set(ByVal Value As Book)
List.Item(Index) = Value
End Set
End Property
End Class
The CollectionBase provides the basic implementation of the IList, IListSource and IEnumerable. Both the IList and IEnumerable interface require consumers to implement methods and properties that support binding, enumerating and looping using the For/Each construct. IList declares methods for adding, inserting, removing and clearing elements from a list. The IListSource declares methods that return a Boolean indicating if there is a list in the object and a method that returns an object that implements the IList interface. The IEnumerable interface declares one method GetEnumerator. These enumerators are based on an interface that supports iterating elements in a collection. Custom collections provide the ability to create a variety of options including custom persistence and custom lookups based on business specifications. The full books custom collection is shown in Listing 19.
Listing 19: The books custom collection
Imports System.Data
Imports System.Xml
Imports System.Xml.Serialization
Public Class books
Inherits CollectionBase
Private dataFile As String = "books.xml"
Default Public Property Item(ByVal Index As Integer) As Book
Get
Return CType(List.Item(Index), Book)
End Get
Set(ByVal Value As Book)
List.Item(Index) = Value
End Set
End Property
Public Function Add(ByVal Item As Book) As Boolean
List.Add(Item)
SaveData()
End Function
Public Function Contains(ByVal value As String) As Boolean
Return List.Contains(value)
End Function
Public Sub Remove(ByVal value As Book)
List.Remove(value)
SaveData()
End Sub
Private Sub BulkAdd(ByVal Item As Book)
List.Add(Item)
End Sub
Public Sub LoadData()
If System.IO.File.Exists("books.xml") Then
Dim xmlFileStream As New IO.FileStream(dataFile, IO.FileMode.Open)
Dim xmlRead As New XmlTextReader(xmlFileStream)
xmlRead.WhitespaceHandling = WhitespaceHandling.None
While xmlRead.Read
If xmlRead.IsStartElement Then
If xmlRead.Name = "ArrayOfBook" Then
xmlRead.ReadStartElement()
Do While xmlRead.Name = "Book"
Dim xmlAuth As String = ""
Dim XMLTitle As String = ""
Dim XMLISBN As String = ""
xmlRead.Read()
If xmlRead.Name = "Author" Then
xmlAuth = xmlRead.ReadString
xmlRead.Read()
End If
If xmlRead.Name = "Title" Then
XMLTitle = xmlRead.ReadString
xmlRead.Read()
End If
If xmlRead.Name = "ISBN" Then
XMLISBN = xmlRead.ReadString
xmlRead.Read()
End If
If xmlAuth <> "" And XMLTitle <> "" And XMLISBN <> "" Then
'add the item to the collection using the bulkadd
Call BulkAdd(New Book(xmlAuth, XMLTitle, XMLISBN))
End If
xmlRead.Read()
Loop ' while book
End If
xmlRead.Read()
End If
End While
xmlRead.Close()
End If
End Sub
Private Sub SaveData()
Dim serializer As System.Xml.Serialization.XmlSerializer = New XmlSerializer(GetType(books))
Dim stream As IO.MemoryStream = New IO.MemoryStream()
serializer.Serialize(stream, List)
Dim BookData As DataSet = New DataSet("Books")
stream.Position = 0
BookData.ReadXml(stream)
stream.Close()
BookData.WriteXml(dataFile)
End Sub
End Class
Once implemented the books custom collection can be used to bind to a dropdown list as shown in Listing 20.
Listing 20: Binding the books collection to a dropdown list.
Dim colbooks As books = New books()
CmbBooks.ValueMember = "Title"
CmbBooks.DisplayMember = "Title"
CmbBooks.DataSource = colbooks
System.Collections.Specialized
The System.Collections.Specialized namespace contains a set of specialized and strongly-typed collections as shown in Table 5. Within the Compact Framework this namespace contains fewer collections than are available within the desktop framework.
Table 5: Collections available in the CF System.Collections.Specialized namespace.
Collection Type |
Description |
HybridDictionary |
Implements the IDictionary interface while the collection contains less than ten items and then switches to a HashTable. |
ListDictionary |
Implements the IDictionary interface using a single linked list. Recommended for collections that contain ten or less items. |
NameValueCollection |
Represents a collection of associated string keys and string values that can be accessed either with the key or with the index |
BitVector32 |
Represents a collection that hold up to 32 boolean values, or a set of small integers that can take up to 32 consecutive bits |
Dictionary Objects
By definition a dictionary object is a data structure that stores a set of key/value pairs. By default dictionaries expose add, find an item by key and remove methods. For example, when adding an element to a dictionary based HashTable, it maintains an array that stores the individual values. These values are added to the Hashtable
by converting the key into an integer and storing it within the array bounds. This approach makes it very quick to find, insert, or retrieve any element from the HashTable. Dictionaries can also be implemented as a linked list. Linked lists are similar to an ArrayList. New items are added to the dictionary at the end of the list. However, finding an element by a key in the list, takes more work. With a HashTable the element is quickly located because there was a function to map the key to the array index. With the linked list the entire list is searched, one element at a time until the requested key is found.
Clearly there's a performance difference between a dictionary implemented as a Hashtable
and a linked list. The Hashtable
provides better performance in adding, finding, and removing elements. So it would seem to make sense to use a Hashtable
for a dictionary in all circumstances, right? Well, no, actually. While the Hashtable
's performance may beat the linked list, it only does so with larger collections. If you are only storing, five elements in your collection, the overhead that comes with the Hashtable
will render it slower than the linked list implementation. For this reason the framework implements a dictionary based on a linked list. The ListDictionary
is the optimal implementation to use for a dictionary when there are ten or less items. When there are more than ten items, the HashTable is the better option.
In most cases it is impossible to know ahead of time the total elements in a collection. For these situations the HybridDictionary
is the appropriate implementation. While a collection has ten or fewer items, the HybridDictionary
internally uses a ListDictionary
to maintain the elements. Once over ten elements, it automatically switches over to a Hashtable
. Listing 21 shows how to create a HybirdDictionary that contains basic catalog information.
Listing 21: Creating a HyrbidDictionary collection
Dim OfficeCatalog As New Specialized.HybridDictionary()
OfficeCatalog.Add("100 No 12 Pencils", "1.49")
OfficeCatalog.Add("100 No 5 Pencils", "1.29")
OfficeCatalog.Add("100 Red Pens", "1.49")
OfficeCatalog.Add("100 Blue Pens", "1.29")
OfficeCatalog.Add("100 Green Pens", "0.89")
The HybridDictionary class takes advantage of the improved performance of a ListDictionary with small collections, and offers the flexibility of transparently switching to a HashTable when the collection grows. If the initial size of the collection is greater than the optimal size for the ListDictionary the collection is stored in a HashTable right away to avoid the overhead of copying elements from the ListDictionary to a HashTable. Like any collection it implements the IEnumerable interface that allows the use of the For/Each construct as shown in Listing 22.
Listing 22: Iterating over a HybridDictionary collection
Dim de As DictionaryEntry
For Each de In OfficeCatalog
MsgBox("The Key is - " & de.Key & " and the value is -" & de.Value)
Next de
The HybridDictionary also exposes a “contains” method that is used to locate a specific key. Listing 23 shows an example of how this is done.
Listing 23: Searching for an item in the HybridDictionary
If OfficeCatalog.Contains("100 Blue Pens") Then
MsgBox("The collection contains the key - 100 Blue Pens")
Else
MsgBox("The collection does not contain the key - 100 Blue Pens")
End If
ListDictionary
The ListDictionary is the implementation of the IDictionary interface based on a single linked list. By default it is smaller and faster than a HashTable for collections that contain ten or less elements. Listing 24 shows an example of how to create a ListDictionary class that contains a set of office catalog items.
Listing 24: Creating a ListDictionary
Dim officecatalog As New Specialized.ListDictionary()
OfficeCatalog.Add("100 No 12 Pencils", "1.49")
OfficeCatalog.Add("100 No 5 Pencils", "1.29")
OfficeCatalog.Add("100 Red Pens", "1.49")
OfficeCatalog.Add("100 Blue Pens", "1.29")
OfficeCatalog.Add("100 Green Pens", "0.89")
Because this collection is designed for smaller lists, it is often used to copy items into a array for retrieval. Listing 25 shows an example of how this can be done.
Listing 25: Copying a ListDictionary to an array and then iterating the values
' Copies the ListDictionary to an array with DictionaryEntry elements.
Dim CatArr(officecatalog.Count) As DictionaryEntry
officecatalog.CopyTo(CatArr, 0)
' Displays the values in the array.
Dim i As Integer
For i = 0 To (CatArr.Length - 1 - 1)
MsgBox("Item Key - " & CatArr(i).Key & " Value - " & CatArr(i).Value)
Next i
NameValueCollection
The NameValueCollection is an association of string keys and values. Inherited from the NameObjectCollectionBase items are accessed by either key or index. As individual elements are added to the collection the capacity is automatically increased. Listing 26 shows an example of how to create a NameValueCollection class that contains a set of office catalog items.
Listing 26: Creating a NameValueCollection
Dim CatInfo As New NameValueCollection
CatInfo.Add("Red Pencils", "1.49")
CatInfo.Add("Green Pencils", "1.75")
CatInfo.Add("Yellow Pencils", "1.98")
CatInfo.Add("Blue Pencils", "1.17")
By default, the .NET Compact Framework doesn’t provide an AppSetting class similar to the full framework. Within the desktop environment a developer access stored application settings by creating a NameValue collection derived from the System.ConfigurationSettings.AppSetting class.
Figure The application settings file
Using a combination of the NameValueCollection and an XML file a similar solution can be created for mobile applications. Within the application first add an XML file that contains the application settings as shown in Figure 8. Listing 27 contains the custom class definition for use in a Compact Framework application.
Listing 27: Application setting class for the Compact Framework
Imports System
Imports System.IO
Imports System.xml
Public Class ClsSettings
Private app_settings As Specialized.NameValueCollection
Private Settings_path As String
Public Function GetAllSettings() As Specialized.NameValueCollection
Return app_settings
End Function
Public Function GetSetting(ByVal keyName As String) As String
Return app_settings(keyName).ToString
End Function
Public Sub UpdateSetting(ByVal KeyName As String, ByVal SettingName As String)
app_settings.Item(KeyName) = SettingName
UpdateSettings()
End Sub
Private Sub UpdateSettings()
Dim tw As XmlTextWriter = New XmlTextWriter(Settings_path, System.Text.UTF8Encoding.UTF8)
tw.WriteStartDocument()
tw.WriteStartElement("configuration")
tw.WriteStartElement("appSettings")
Dim i As Integer
For i = 0 To (app_settings.Count - 1)
tw.WriteStartElement("add")
tw.WriteStartAttribute("key", String.Empty)
tw.WriteRaw(app_settings.GetKey(i))
tw.WriteEndAttribute()
tw.WriteStartAttribute("value", String.Empty)
tw.WriteRaw(app_settings.Get(i))
tw.WriteEndAttribute()
tw.WriteEndElement()
Next
tw.WriteEndElement()
tw.WriteEndElement()
tw.Close()
End Sub
Public Sub New()
Settings_path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName.CodeBase) & "\appsettings.xml"
If File.Exists(settings_path) Then
Dim xdoc As XmlDocument = New XmlDocument
xdoc.Load(settings_path)
Dim root As XmlElement = xdoc.DocumentElement
Dim nodelist As System.Xml.XmlNodeList = root.ChildNodes.Item(0).ChildNodes
app_settings = New Specialized.NameValueCollection
Dim i As Integer
For i = 0 To (nodelist.Count - 1)
app_settings.Add(nodelist.Item(i).Attributes("key").Value, nodelist.Item(i).Attributes("value").Value)
Next
End If
End Sub
End Class
Additionally, Listing 28 shows how to retrieve and display the available application settings within a list box from the front end application.
Listing 28: Retrieving all the application settings
Dim lvarSettings As New ClsSettings
Dim lvarItems As Specialized.NameValueCollection
lvarItems = lvarSettings.GetAllSettings
' print out
Dim myEnumerator As IEnumerator = lvarItems.GetEnumerator()
Dim s As String
For Each s In lvarItems.AllKeys
txtSettings.Text = txtSettings.Text & vbCrLf & "Key: " & s & " value:" & lvarItems(s)
Next s
Once loaded into the list box, the setting item can be selected. Listing 29 shows how the selected value is then used to retrieve an individual application setting.
Listing 29: Retrieving an individual application setting.
Dim lvarSettings As New ClsSettings
Dim lvarItems As Specialized.NameValueCollection
lvarItems = lvarSettings.GetAllSettings
' load the items
Dim myEnumerator As IEnumerator = lvarItems.GetEnumerator()
Dim s As String
For Each s In lvarItems.AllKeys
CmbItems.Items.Add(s)
Next s
BitVector32
TheBitVector32 collection implements a data structure that stores Boolean values and small integers in thirty two bits of memory. This collection is based on the BitArray class that stores one bit Boolean values. However, because the BitVector32 is implemented as a data structure instead of a class it is inherently more efficient. Listing 30 shows an example of defining a BitVector32 collection that holds a series of Booleans.
Listing 30: Creating a BitVector32 application
Dim bv As New BitVector32()
bv(1) = True
BitVector32 exposes a CreateSection method that is used to create a series of smaller more manageable integer sections. By definition a section is a series of the smallest number of consecutive bits that contain the maximum value defined in the CreateSection method. Creating more than one BitVector32.Section defines separate data structures that are longer than one bit. Listing 31 contains an example of how this can be done.
Listing 31: Creating three sections within a BitVector32 collection
Dim bv As New BitVector32()
' create three sections, of 4, 5, and 6 bits each
Dim se1 As BitVector32.Section = BitVector32.CreateSection(15)
Dim se2 As BitVector32.Section = BitVector32.CreateSection(31, se1)
Dim se3 As BitVector32.Section = BitVector32.CreateSection(63, se2)
' set each section at a given value
bv(se1) = 10
bv(se2) = 20
bv(se3) = 40
' read them back
msgbox(bv(se1))
msgbox(bv(se2))
msgbox(bv(se3))
By default a BitVector32.Section created with a maximum value of one acts as a Boolean. Passing a single 32-bit integer to the default constructor initializes all the elements into a single section using the following code.
bv = new BitVector32(-1)
The Data property is used to set or return the internal 32-bit value. Using this property enables the formatting of the Boolean as shown in the code below.
Textbox1.text = bv.Data.ToString("X")
System.Collections.Generic
The term generic is defined as an item that isn’t tied to a specific brand name. Generic items are available as close as the nearest grocery store. Stored next to the name brand items are usually the plainly packaged generic versions of these same items. These generic items expose a set of known properties and behaviors. For example, generic laundry soap guarantees that it will clean our clothes. Many times we may opt to purchase a name brand item because we know that it guarantees additional or enhanced properties over basic generic items.
The System.Collections.Generic namespace contains interfaces and classes that define generic collections. Fundamentally, generics are classes, structures, interfaces, and methods that have placeholders or type parameters for one or more storage types. For example, a generic collection class might use a type parameter as a placeholder for the type of objects it stores. These generic type parameters appear as the types of its fields, and the parameter types of its methods. A generic method might use its type parameter as the type of its return value, or as the type of one of its formal parameters. The keyword Of is used to create generics. Listing 32 illustrates a generic class definition.
Listing 32: A simple generic class definition
Public Class Generic(Of T)
Public Field As T
End Class
Generic types are parameterized with one or more data types. This allows the application developer to tailor the data types to specific requirements. During development each generic type can declare several different elements. However, each declared elements all perform the identical logic, no matter what data types they are using. For example, Listing 33 shows an example of a generic class.
Listing 33: A generic class
Public Class Gen(Of T)
Dim dataType As T
Public Property Val() As T
Get
Return dataType
End Get
Set(ByVal value As T)
dataType = value
End Set
End Property
End Class
The Gen class is defined as a generic class. As described above the Of keyword is used to declare it as generic. The T next to the Of represents a place holder for the data-type that will be passed when an instance of the class is created. The actual data types are defined as a substitute for the type parameters when the class is initialized. This establishes a new generic class with the chosen types substituted everywhere that the type parameters appear. For example, listing 34 shows an example of creating an instance of the Gen class using a string.
Listing 34: Initializing a string based generic class.
Dim mystring As New Gen(Of String)
mystring.Val = "hello world"
msgbox(mystring.Val)
This same class can be initialized using an integer as shown in Listing 35.
Listing 35: Initializing an integer based generic class.
Dim myInt As New Gen(Of Integer)
myInt.Val = 5
msgbox(myInt.Val)
Figure 9 The terms used in a Generic Type
A generic type definition as shown in Figure 9 is a class structure or interface declaration that functions as a template, with placeholders for the types it can contain or use. Generic type parameters are the placeholders in a generic type or method definition. A generic method definition is a method with two parameter lists: a list of generic type parameters, and a list of formal parameters. Type parameters can appear as the return type or as the types of the formal parameters.
A constructed generic type is the result of specifying types for the generic type parameters with a generic type definition. The general term "generic type" includes both constructed types and generic type definitions. A generic type argument is any type that is substituted for a generic type parameter. For example, Listing 36 creates a generic method that returns the highest value in a series.
Listing 36: Generic method for returning largest number
Public Function Max(Of T As IComparable)(ByVal val1 As T, ByVal val2 As T) As T
Dim retVal As T = val2
If (val2.CompareTo(val1) < 0) Then
retVal = val1
End If
Return retVal
End Function
Listing 37 shows an example of calling this generic method with a double and integer data type.
Listing 37: Calling the generic method
Dim MaxInt As Int32 = Max(Of Double)(64, 3)
Dim MaxDouble As Double = Max(Of Double)(12.48, 99.12)
Although the code in a generic type definition should be as type independent as possible, in certain situation their may be a certain capability required for any data type that is supplied to the generic type. For example, if you want to compare two items for the purpose of sorting collating, their data type must implement the IComparable interface. This type of restriction is enforced by adding a constraint to the type parameter as shown in Listing 38.
Listing 38: Implement a generic constraint.
Public Class StudentInformation(Of t As {IComparable, IDisposable, Class, New})
' Insert code that defines class members.
End Class
Generic Collections
As we have seen earlier except for a few specialized collections the majority of collections provided by the .NET Framework are weakly typed and not type safe. Weakly typed collections can cause both performance and maintenance issues with a business object. Mainly because there are no inherent safeguards for limiting the types of objects stored in the collection. Essentially a weakly typed collection is only capable of handling the type it’s defined for. These types of collections aren’t generic – they have to declare their brand name up front. If you build and expose a collection of integers, then inadvertently pass that collection a date the running code fails.
Type safe means that whenever you add an object to the collection it is checked at compile time. This means that the generic type should be safe if you pass a wrong data type to the collection. It will throw an error during the compile time and not in the run time code. This simple change improves performance because no type casting is necessary at run time. However, performance and speed are not the main aspects to use generics, but the maintainability and cleaner code.
The Generic namespace class also provides some predefined generic classes as shown in Table 6. For example, the List generic class within that namespace is synonymous with the typical System.Collections.ArrayList class. Listing 39 shows an example of adding items to a string based instance of this class.
Listing 39: A string based instance of the List generic class
Dim CustList As New List(Of String)
CustList.Add("CEPF")
CustList.Add("JACK")
CustList.Add("MAYN")
CustList.Add("JACK")
Table 6: Built in generic namespaces
Generic Class |
Description |
Dictionary |
The Dictionary generic class provides a mapping from a set of keys to a set of values. |
KeyValuePair |
The KeyValue generic class defines a key/value pair that can be set or retrieved. |
LinkedList |
LinkedList is a general-purpose linked list that supports enumerators and implements the ICollection interface. |
LinkedListNode |
Each element of the LinkedList collection is a LinkedListNode. The LinkedListNode contains a value, a reference to the LinkedList that it belongs to, a reference to the next node, and a reference to the previous node. |
List |
The List class is the generic equivalent of the ArrayList class. It implements the IList generic interface using an array whose size is dynamically increased as required. |
Queue |
The Queue generic class defines a first-in, first-out collection of objects. |
SortedList |
The SortedList generic class defines a a collection of key/value pairs that are sorted by key based on the associated IComparer implementation. |
Stack |
The Stack generic class defines a variable size last-in-first-out (LIFO) collection of objects. By default the default initial capacity for a Stack is ten. |
This namespace also exposes the same types of collections we have seen before like the Queue class. For example, the following creates a queue class that operates on a string.
Public stringQ As New System.Collections.Generic.Queue(Of String)
In this Queue class the stringQ works exclusively with String values. Because stringQ is specific for String instead of being generalized for Object values, this removes the need to have late binding or type conversion. Ultimately this saves execution time and reduces run-time errors.
Summary
Business objects are an important aspect of application development. In this chapter we looked at how they are developed using the concepts of OO adapted for the SOA architecture. This combination helps solves the traditional problems that are associated with a strictly OO based architecture and creates a set of loosely coupled services for mobile applications. Collections and generics are used to help further create more scalable applications that more closely match the data structures they describe. Ultimately, the goal is to abstract out the underlying storage architecture for better code reuse. When building mobile applications these are the key ways to manipulate and store application data.
Comments
- Anonymous
February 17, 2007
Download Samples Download PDF Overview The drive to connect people, process and devices is a never ending