Introduction
I started reading Martin Fowler's Patterns of Enterprise Architecture recently. I became confused with his description of the Transaction Script Pattern, so I created a Visual Studio Solution that implements the examples he used in the chapter. Fowler does not provide code samples/solutions on his website, and I could not find anyone else who did a similar project on CodeProject, so I started from scratch. The attached Zip file includes a database script and a VS2008 solution to help any one who is working though the same text.
Background
This code is meant to accompany Fowler's Patterns of Enterprise Application Architecture (14th printing), pages 110-115.
Using the Code
The accompanying Zip file includes several files: DomainLogicPatternsDatabase.sql should be run to set up the database. You need to configure the App.config to connect to the database.
The FowlerTransactionScript solution includes two projects (the DomainLogic project and a Console project). Domain Logic is based on the Java code that Fowler uses in the project to demonstrate a business tier construction. I added the interfaces to make things easier to understand. The Console project represents the UI Layer.
There are a couple of things to note:
- The UI layer references
System.Data
as the DataTable
is the data structure used to hold data across layers. This is very close to a Table Module Pattern. Perhaps, he should have used a generic data structure to really show the difference? - The business logic is implemented in the
ReconignitionService.CalculateRevenueRecognitions
function.
datatable = gateway.FindContract(contractId);
decimal totalRevenue = Decimal.Parse(datatable.Rows[0][1].ToString());
DateTime recognitionDate = DateTime.Parse(datatable.Rows[0][2].ToString());
string contractType = datatable.Rows[0][5].ToString();
decimal revenuePiece = 0;
switch (contractType)
{
case "S":
revenuePiece = totalRevenue / 3;
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate);
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate.AddDays(60));
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate.AddDays(90));
break;
case "W":
gateway.InsertRecognition(contractId, totalRevenue, recognitionDate);
break;
case "D":
revenuePiece = totalRevenue / 3;
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate);
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate.AddDays(30));
gateway.InsertRecognition(contractId, revenuePiece, recognitionDate.AddDays(60));
break;
default:
break;
}
If this code was replaced with TSQL and placed in the database, the ReconignitionService.CalculateRevenueRecognitions
would only be calling a Stored Procedure. I wonder if it is still a TransactionScript Pattern? On one hand, the interface did not change. But on the other, DomainLogic is a smack dab in the the data layer.
Domain Logic
The accompanying Zip file includes two projects - the Domain Logic Layer Project and the User Interface (Console) project. I did not hook up a database to this project. If you want to see how to do that, use the project found here.
The key classes in the Domain Logic are Product and Contract. Unfortunately, Fowler's code snippets are not correct and he does not present an entire solution so I had to cobble together some things to get to his intent. In this example, you create a product, then associate that product to one (or more) contracts and then calculate the recognition via the product. This seems counter-intuitive to me - I would assume that contracts would be responsible for calculating their own recognitions, but that is not how he set it up.
One other area where I differed from the book is around Recognition Strategies. He used an abstract class, I used an interface. Both gets you to the same place but as a general rule, Interfaces > abstract classes and tie goes to the runner.
Points of Interest
None.
History
- Version 1.0 - 1/21/2009.
- Version 2.0 - 2/03/2009
- Added Domain Logic section