FREE hit counter and Internet traffic statistics from freestats.com

Tuesday, November 16, 2004

Organizing Domain Logic: Table Module

The second pattern for representing domain logic is the Table Module. As the name implies this pattern calls for a Business Component to map to a table in the database. The component then contains all the domain logic methods required to manipulate the data. There are two key considerations here.

First, although the name refers to a table, Table Module can also be used to abstract frequently used sets of data created by joining multiple tables together in a view or query. This makes dealing with more complicated data much easier for the caller to the Business Components.

Second, the core characteristic of each component built as a Table Module is that, unlike Domain Model, it has no notion of identity. In other words, each Table Module object represents a set of rows rather than a single row and therefore in order to operate on a single row, the methods of the table module must be passed in identifiers.

When a method of a Table Module is called, it performs its logic against a set of rows passed into it. In Framework applications this maps to a DataSet and is therefore a natural way to represent domain logic. In fact, using Typed DataSets with Table Module is particularly effective since it promotes strong typing at design time leading to fewer runtime errors and better control over the data flowing through the application.

A common approach to handling this is to create a Layer Supertype (a pattern also discussed by Fowler) or base class for all of the Table Modules that accepts a DataSet in its constructor. This also allows the Business Components to be tested without a live connection to a database.

To implement a Table Module approach in the retail application example you could create an abstract BusinessComponentBase class like that shown here. This class is responsible for accepting the DataSet that the class will work on, exposing individual rows in the DataSet using the default (VB) or indexer (C#) property, and exposing the entire set of rows in a readonly property.

As you can see one of the advantages to using Table Module over Transaction Script is that it is easier to encapsulate responsibilities with the appropriate objects. Here the Customers class contains the SendEmail and CheckCredit methods that can be called independently whereas the Transaction Script shown previously would have included inline code to handle this.
The code to implement the BusinessComponentBase class can be seen below.


Public MustInherit Class BusinessComponentBase
Private _ds As DataSet
Private _pk As String
Protected Sub New(ByVal data As DataSet)
_ds = data
_pk = _ds.Tables(0).PrimaryKey(0).ColumnName
End Sub
Default Protected ReadOnly Property Item(ByVal id As Integer) As DataRow
Get
Dim f As String = _pk & " = " & id
Return _ds.Tables(0).Select(f)(0)
End Get
End Property
Protected ReadOnly Property Items() As DataSet
Get
Return _ds
End Get
End Property
End Class

Note that the protected constructor finds the primary key column and stores its value in a private variable used by the Item property to select and return a particular DataRow.


This class can then be inherited by Orders and Customers. The Orders class in C# is shown here.

public class Orders : BusinessComponentBase
{
public new OrdersDs Items
{ get { return (OrdersDs)base.Items; }
}
public Orders(OrdersDs orders):base(orders)
{ }
public ShipType GetShipType(long orderId)
{
// Return the shipping type for the order
}
public double GetShippingCost(long orderId)
{
// Calculate the shipping costs for the order
}
public void SaveOrder(long orderId)
{
// Save the specific order to the database
}
public void SaveOrder()
{
// Save all the orders to the database
}
public long Insert(long productId, int customerId,
long quantity, ShipType ship)
{
// Insert a new row in the DataSet
}
}

The main point to notice here is that the constructor accepts a DataSet of type OrdersDs which is a Typed DataSet. The class then shadows the Items method in order to return a strongly typed DataSet. Also, this is a good place to take advantage of overloading as in the SaveOrder method which can be used to save either one order or all of the orders in the DataSet.

A client can then instantiate the Orders class passing into it the OrdersDs DataSet.
Orders o = new Orders(dsOrders);o.Save(123324);

1 comment:

Beden said...

When people think of sex, they often think of orgasm as the ultimate way to achieve pleasure. Female orgasm, in particular, is often seen to be proof of sexual success. To achieve High-end Sexual Arousal - visit
Hottest xxx videos
XXX Porn videos
SEX Movies Collections