Thursday, December 20, 2018

Table Module Pattern

A single instance that handles the business logic for all rows in a database table or view.

Business Logic that involves all Rows in a Single Database Table

Business Logic means some Computations or Calculations. If it is some Filtering or Records, it should be done in the Data Access Layer rather than in Domain Layer or App. Service layer.

As we are mixing Commands and Queries in single class, that is why cause confusing. 


About Domain Model



In Domain Model, Order Objects Corresponds to One Order. Business Methods work on just one Order. Order Class encapsulate the Domain Logic related to one Order.

Domain Logic that involves Collection of Orders goes into the Domain Services Class.

One of the key messages of object orientation is bundling the data with the behavior that uses it. 

The traditional object-oriented approach is based on objects with identity, along the lines of Domain Model (116). 

Thus, if we have an Employee class, any instance of it corresponds to a particular employee.

This scheme works well because once we have a reference to an employee, we can execute operations, follow relationships, and gather data on him.

Table Module organizes domain logic with one class per table in the database, and a single instance of a class contains the various procedures that will act on the Table Data. That Table Data involve both Single Row in the DB or Multiple Rows int the DB.

Table Module ==> Single Row + Multiple Rows Domain Logic

The primary distinction with Domain Model is that, if you have many orders, a Domain Model will have one order object per order while a Table Module will have one object to handle all orders.

Domain Model
Single Row Domain Logic ==> Entity
Multiple Row Domain Logic ==> Domain Service

I think Martin Fowler Definition of Domain Model is quite about the Multiple Row Domain Logic.

=====================================

Table Module

A Table Module organizes domain logic with one class per table in the database. 

All Domain Logic related to a DB Table (either one Order Domain Logic or Multiple Order Domain Logic) goes into one class.

Single instance of a class contains ALL Domain Logic Methods (both Single Row or Multiple Row Domain Logic) In case of Orchestration (When Multiple Tables are Involved) we need another Domain class

The primary distinction between Table Module and Domain Model (116) is that, if you have Domain Logic involving many orders

1- A Domain Model (116) will have one order object per order. This Object will act on the data related to that Entity, (Data is one Row in DB). 

2-Table Module will have one object to handle all orders in the DB Table. In case of Orchestration (When Multiple Tables are Involved) we need another Domain class

============================================


Table module pattern


The short definition for the Table Module Pattern is: “a single instance that handles the business logic for all rows in a database table or view”.
The Table Module pattern introduces a single object to handle all the requested action towards a database table or view. It combines the data and behavior in one class and also keeps a tight linkage with relational database. An instance of the Table Module object looks like a regular objects, but in fact it does not have hold the identity which the object is currently working with. The difference between Domain Model and Table Module is that, for Domain Model, several object instances will be used to deal with different records of the database table; however, with Table Module, only one object will be used and it deals with all records of the database table.

When to Use It

The Table Module is best to be sued with table-oriented data. It also push the data structure to the center of the application, which makes easy for programmer to access the data structure. The drawback of the Table Module is that it does not have the full power of objects when dealing with complex business logic. In such a case, the Domain model pattern with Active record pattern is a better choice. If the application only use few shared common table-oriented data structure, then the Table module pattern is better than the combination of Domain model pattern and Active record pattern.



Practical PHP Patterns: Table Module


The Table Module pattern is implemented by coding a class that encapsulates all the interaction with a database table. The usage of such a class may be singleton-like or more instances can be created to perform operations on subsets of the original table.
Given that the relationship between Table Modules and tables is biunivocal, often different Table Modules can be coordinated from client code or from an upper layer. This pattern can also be applied to views, or queries, since both are virtual tables and produce a record set which can be passed to the Table Module.

Modelling phase 

In this modelization there are no single objects for the rows of the table, like in other patterns such as Active Record or Row Data Gateway. The Table Module encapsulates all the business logic in a database-centric approach, and its method signatures use primitive values for parameters and return type, or at most data containers such as Value Objects.
The Table Module composes a record set, or a database connection. However when using a connection object it is less versatile (queries to produce virtual tables can't be outsourced to maintain orthogonality) and can cross the boundary of another pattern, the Table Data Gateway. The more the dependencies are reduced, the more the table data can be filtered or altered before the Table Module receives the set of rows, enhancing the reusability of the class.

Pros and cons

A Table Module ties the client code to the entities present in a relational database (although this is true in some way for many patterns oriented to database interaction.) It is however a pattern that strives to keep data with its related behavior and wraps external infrastructure like databases in something that can be substituted in testing or in other environments. Still more clever than scattering queries in many different php scripts.
Ideally SQL is not needed to use a Table Module from the client point of view: it is either outsourced into other classes that produce a record set which the Table Module examines, or encapsulated by the Table Module itself; this pattern is a simple form of Repository, that still conforms to the data structures defined by the database. The primary difference is the absence of a basic entity class, so we can't talk about an access to an in-memory collection of objects; though, it is a stronger form of encapsulation in certain cases, because an entity class for the single row may not be needed nor have any logic.
This pattern is also much simpler than the Domain Model one: there is no translation of data between objects and rows. The lack of mapping can be a disadvantage - coupling to the schema - but also an advantage in implementation speed, particularly if you want to interface with a database for interoperability. Not all web applications need a Domain Model: some are glue code, some are interfaces to other software systems. In practice, the time spent to implement a complex model and its mapping can be prohibitive for a throw-away application or even for a small or medium sized project that does not pass the complexity threshold.
Beware that if you already encapsulate large computations on the data, you may want to push the related logic in the database for better performance, defining it with SQL queries. This is done with a different pattern, the Table Data Gateway, but can be more difficult and heavier to test effectively in automated test suites. Essentially if you use SQL you're tied to create a database and a connection whenever you want to test your business logic, and even if you pass a PDO object or another abstraction to the table module, a lightweight (read easier to employ in tests) database such as Sqlite may not support all the features you use in your SQL queries. Add that this process should be done for every single test to promote their isolation, and you get the picture.

Samples

It makes sense to implement this pattern when the table data as a whole is more significant than a single row. Thus, the table may not contain entities but it's likely to store values or associating entities. In fact, the sample code deals with an example where the dataset is treated as a whole: a table containing analytics data, such as the browser and resolution of uses that have visited a website.


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);

No comments:

Post a Comment