Enterprize Design Patterns PDF
Enterprize Design Patterns PDF
[email protected]
Instituto Superior de Engenharia do Porto
Introduction
Enterprise Applications
Sample problem
Business entities
Business logic and data access
Some improvements
Sample application
Patterns for distributed applications
Synopsis
Conclusions
Part 1
“Each pattern describes a problem that
occurs over and over again in our
environment and then describes the
core of the solution to that problem in
such a way that you can use this
solution a million times over without
ever doing it the same way twice.”
Christopher Alexander
(architect)
“A Software Design Pattern names,
abstracts, and identifies the key aspects
of a common design structure that
make it useful for creating a reusable
object-oriented design.”
Design Patterns-Elements of Reusable Object-oriented
Software, Gamma et al. (Gang of Four)
a set of best practices
Pattern overload
Experience-based validation
8
name Contributes to the pattern
vocabulary
synopsis Short description of the problem the
pattern will solve.
forces Requirements, considerations, or
necessary conditions
solution The essence of the solution
counter forces Reasons for not using the pattern.
related patterns Possible alternatives in the design.
9
GoF Gang of Four
POSA Pattern-Oriented Software Architecture
WordProcessor SpreadSheet
*
RevenueRecognition
+ dateRecognition DataBase
+ amount
«table»
TRevenueRecognitions
+ «Column» ID : int
+ «Column» contractID : int
+ «Column» dateRecognition : date
+ «Column» amount : currency
«table»
«table»
TContracts
«table» TProducts
TCustomers + «Column» ID : int
+ «Column» ID : int
+ «Column» productID : int
+ «Column» ID : int + «Column» type : varchar
+ «Column» customerID : int
+ «Column» name : varchar + «Column» name : varchar
+ «Column» revenue : currency
+ «Column» dateSigned : date
public interface IRevenueRecognition
{
void CalculateRevenueRecognitions(int contractID);
object GetContracts();
object GetCustomers();
object GetProducts();
}
Part 4
How to represent:
One entity, e.g. Customer?
Collections, e.g., List of customers?
Networked/complex objects, e.g., production plan?
XML
IList / List
XML
Product
+ Type : int
+ Name : string
+ ID : int
Product Contract
Customer
+ Type : int + Revenue : decimal
+ Name : string + DateSigned : DateTime + Name : string
+ ID : int + CustomerID : int + ID : int
+ ProductID : int
+ ID : int
* + RevenueRecognitions
RevenueRecognition
+ DateRecognition : DateTime
+ Amount : decimal
+ ContractID : int
+ ID : int
An XML document (or string) representing an
entity’s structure
<product>
<id>123</id>
<name>SuperWriter 7.3</name>
<type>Word Processor</type>
</product>
A DataSet (or derived class) to hold tabular
data (eventually directly from a data source)
A class implementing the ResultSet interface to
hold tabular data (eventually directly from a data
source)
A library collection class (e.g. LinkedList)
LinkedList
Part 5
Table oriented BLL
Table Module
DAL
Table Data Gateway
Object oriented
BLL
Domain Model
Active Record
DAL
BLL
Data Mapper
Part 5.1
UI
Uses the
platform’s
ResultSet for
«table module» sharing entity data
BLL beteween layers
+ Contract ( )
+ RecognizedRevenue ( [in] contractID : int , [in] asOf : DateTime ) : Money
+ CalculateRevenueRecognitions ( [in] contractID : int )
+ GetContracts ( ) : DataSet
+ GetContractsByProduct ( [in] productID : int ) : DataSet
+ GetContractsByCustomer ( [in] customerID : int ) : DataSet
Customer
+ Customer ( )
+ GetCustomers ( ) : DataTable
Product
+ Product ( )
+ GetProducts ( ) : DataTable
Pattern
Business
entity
+ CustomerGateway ( )
+ GetCustomers ( ) : DataTable
ContractGateway
ProductGateway + ContractGateway ( )
+ InsertRecognition ( [in] contractID : int , [in] recognitionDate : DateTime , [in] amount : decimal ) : int
+ ProductGateway ( ) + GetContracts ( ) : DataSet
+ GetProducts ( ) : DataTable + GetContractByID ( [in] contractID : int ) : DataSet
+ GetContractsByProduct ( [in] productID : int ) : DataSet
+ GetContractsByCustomer ( [in] customerID : int ) : DataSet
BaseGateway
# «property» CurrentTransaction : OleDbTransaction
- CONNSTR : string = @"Provider=..."
+ BaseGateway ( )
# GetConnection ( [in] open : bool ) : OleDbConnection
# ExecuteQuery ( [in] cnx : OleDbConnection , [in] sql : string ) : DataSet
# ExecuteNonQuery ( [in] cnx : OleDbConnection , [in] sql : string ) : int
# ExecuteNonQuery ( [in] tx : OleDbTransaction , [in] sql : string ) : int
# ExecuteNonQuery ( [in] tx : OleDbTransaction , [in] cmd : OleDbCommand ) : int
+ BeginTransaction ( )
+ CommitTransaction ( ) 42
+ RoolbackTransaction ( ) ISEP/IP
# «get» CurrentTransaction ( ) : OleDbTransaction P
/ User : Actor1 / GUI / ClassifierRole1 : Contract / ClassifierRole2 : Contract
Gateway
1 : \Form_Load\
2 : GetContracts ( )
3 : GetContracts ( )
4 : GetConnection ( open )
1 : \btnCalcRevenues_Click\
2 : CalculateRevenueRecognitions (
contractID )
3 : \new\ / ClassifierRole2 : Contract
Gateway
4 : GetContractByID ( contractID )
5 : BeginTransaction ( )
7 : CommitTransaction ( )
public void CalculateRevenueRecognitions(int contractID) Returns a join of
{
DAL.ContractGateway dal = new DAL.ContractGateway(); TContracts and
DataSet ds = dal.GetContractByID(contractID);
TProducts
string prodType = (string)ds.Tables[0].Rows[0]["type"];
decimal totalRevenue = (decimal)ds.Tables[0].Rows[0]["revenue"];
DateTime recDate = (DateTime)ds.Tables[0].Rows[0]["dateSigned"];
dal.BeginTransaction();
switch (prodType) {
case "PT":
dal.InsertRecognition(contractID, recognitionDate, totalRevenue);
break;
case "FC":
decimal[] allocs = Money.Allocate(totalRevenue, 3);
dal.InsertRecognition(contractID, recDate, allocs[0]);
dal.InsertRecognition(contractID, recDate.AddDays(60), allocs[1]);
dal.InsertRecognition(contractID, recDate.AddDays(90), allocs[2]);
break;
case "BD":
decimal[] allocs = Money.Allocate(totalRevenue, 3);
dal.InsertRecognition(contractID, recDate, allocs[0]);
dal.InsertRecognition(contractID, recDate.AddDays(30), allocs[1]);
dal.InsertRecognition(contractID, recDate.AddDays(60), allocs[2]);
break;
} Explicit transaction control
dal.CommitTransaction();
} ☺/
public int InsertRecognition(int contractID,
DateTime recognitionDate,
decimal amount)
{
OleDbCommand sqlcmd = new OleDbCommand(
"INSERT INTO TRevenueRecognitions
(contractID, dateRecognition, amount)
VALUES (?, ?, ?)",
CurrentTransation.Connection,
CurrentTransation
);
sqlcmd.Parameters.Add("@cid", contractID);
sqlcmd.Parameters.Add("@dt", recognitionDate);
sqlcmd.Parameters.Add("@amt", amount);
return ExecuteNonQuery(CurrentTransation, sqlcmd);
}
Part 5.2
UI
* + RevenueRecognitions
RevenueRecognition
+ DateRecognition : DateTime
+ Amount : decimal
+ ContractID : int
+ ID : int
Contract
+ Contract ( )
+ RecognizedRevenue ( [in] contractID : int , [in] asOf : DateTime ) : Money
+ CalculateRevenueRecognitions ( [in] contractID : int )
+ GetContracts ( ) : IList
+ GetContractsByProduct ( [in] productID : int ) : IList
+ GetContractsByCustomer ( [in] customerID : int ) : IList
Customer
+ Customer ( )
+ GetCustomers ( ) : IList
Product
+ Product ( )
+ GetProducts ( ) : IList
CustomerGateway
+ CustomerGateway ( ) ContractGateway
+ GetCustomers ( ) : IList
- CreateCustomerObject ( [in] r : DataRow ) : Customer + ContractGateway ( )
+ InsertRecognition ( [in] contractID : int , [in] recognitionDate : DateTime , [in] amount : decimal ) : int
+ GetContracts ( ) : IList
+ GetContractByID ( [in] contractID : int ) : Contract
ProductGateway + GetContractsByProduct ( [in] productID : int ) : IList
+ GetContractsByCustomer ( [in] customerID : int ) : IList
+ ProductGateway ( ) - CreateContractObject ( [in] r : DataRow ) : Contract
+ GetProducts ( ) : IList - CreateRevenueRecognitionObject ( [in] r : DataRow ) : RevenueRecognition
- CreateProductObject ( [in] r : DataRow ) : Product
BaseGateway
# «property» CurrentTransaction : OleDbTransaction
- CONNSTR : string = @"Provider=..."
+ BaseGateway ( )
# GetConnection ( [in] open : bool ) : OleDbConnection
# ExecuteQuery ( [in] cnx : OleDbConnection , [in] sql : string ) : DataSet
# ExecuteNonQuery ( [in] cnx : OleDbConnection , [in] sql : string ) : int
# ExecuteNonQuery ( [in] tx : OleDbTransaction , [in] sql : string ) : int
# ExecuteNonQuery ( [in] tx : OleDbTransaction , [in] cmd : OleDbCommand ) : int
+ BeginTransaction ( )
+ CommitTransaction ( )
+ RoolbackTransaction ( )
51
# «get» CurrentTransaction ( ) : OleDbTransaction ISEP/IP
P
/ User : Actor1 / GUI / ClassifierRole1 : Contract
1 : \Form_Load\
2 : GetContracts ( )
4 : GetContracts ( )
5 : GetConnection ( open )
7 : \new\ / IList
8 : \new\
/ ClassifierRole3 : Contract
52
ISEP/IP
P
/ GUI / bll : Contract
1 : \btnCalcRevenues_click\
Sequence
2 : CalculateRevenueRecognitions (
contractID ) CalculateRevenues
3 : \new\ / dalC : ContractGateway
4 : GetContractByID ( contractID )
5 : CreateContractObject ( r )
6 : \new\
/ c : Contract
7 : \new\
/ dalP : ProductGateway
8 : GetProductByID ( productID )
9 : CreateProductObject ( r )
10 : \new\
/ p : Product
11 : BeginTransaction ( )
14 : CommitTransaction ( )
public void CalculateRevenueRecognitions(int contractID)
{
DAL.ContractGateway dalC = new DAL.ContractGateway();
Entities.Contract c = dalC.GetContractByID(contractID);
DAL.ProductGateway dalP = new DAL.ProductGateway();
TM.Entities.Product p = dalP.GetProductByID(c.ProductID);
dalC.BeginTransaction();
switch (p.Type) {
case "PT":
dalC.InsertRecognition(contractID, c.DateSigned, c.Revenue);
break;
case "FC":
decimal[] alcs = Money.Allocate(c.Revenue, 3);
dalC.InsertRecognition(contractID, c.DateSigned, allocs[0]);
dalC.InsertRecognition(contractID, c.DateSigned.AddDays(60), alcs[1]);
dalC.InsertRecognition(contractID, c.DateSigned.AddDays(90), alcs[2]);
break;
case "BD":
decimal[] alcs = Money.Allocate(c.Revenue, 3);
dalC.InsertRecognition(contractID, c.DateSigned, allocs[0]);
dalC.InsertRecognition(contractID, c.DateSigned.AddDays(30), alcs[1]);
dalC.InsertRecognition(contractID, c.DateSigned.AddDays(60), alcs[2]);
break;
}
dalC.CommitTransaction();
}
Part 5.3
GUI
+ Customer ( )
- _Customer
# Customer ( [in] row : DataRow )
Contract
0..1 + LoadById ( [in] customerID : int ) : Customer
- CustomerID : int + LoadAll ( ) : IList
- DateSigned : DateTime + Save ( )
- ProductID : int
- Revenue : decimal
# «property» Product : Product
+ Contract ( ) RevenueRecognition
# Contract ( [in] row : DataRow )
# Contract ( [in] dsContractAndRecognitions : DataSet ) - RevenueRecognitions + Amount : decimal
+ RecognizedRevenue ( [in] asOf : DateTime ) : Money * + DateRecognition : DateTime
+ CalculateRevenueRecognitions ( ) + ID : int
+ LoadById ( [in] contractID : int ) : Contract
+ LoadByProduct ( [in] productID : int ) : IList + RevenueRecognition ( [in] id : int , [in] dt : DateTime , [in] amt : decimal )
+ LoadByCustomer ( [in] customerID : int ) : IList + RevenueRecognition ( [in] dt : DateTime , [in] amt : decimal )
+ LoadAll ( ) : IList
+ Save ( ) inner private
# AddRecognition ( [in] recognitionDate : DateTime , [in] amount : decimal ) class
# «get» Product ( ) : Product
DBHelper
1 : \Form_Load\
2 : LoadAll ( )
3 : ExecuteQuery ( sql )
4 : \new\ / IList
5 : Contract ( row )
/ ClassifierRole2 : Contract
6 : \Add\
foreach
returned row
Networks of objects
E.g. Invoice heading relates to invoice details
Invoice details refers to Products
Products refers to Suppliers
…
What to do?
Load them all into memory?
How to disallow multiple in-memory copies
62
Pattern
foreach calculated
recognition
7 : Save ( )
8 : BeginTransaction ( )
9 : ExecuteTransactedNonQuery ( sql
)
10 : ExecuteTransactedNonQuery ( sql
)
foreach RevenueRecognition
object in _RevenueRecognitions
11 : CommitTransaction ( )
public void CalculateRevenueRecognitions()
{
switch (this.Product.Type) {
case "PT":
AddRecognition(this.DateSigned, this.Revenue);
break;
case "FC":
decimal[] allocsFC = Money.Allocate(Revenue, 3);
AddRecognition(DateSigned, allocsFC[0]);
AddRecognition(DateSigned.AddDays(60), allocsFC[1]);
AddRecognition(DateSigned.AddDays(90), allocsFC[2]);
break;
case "BD":
decimal[] allocsBD = Money.Allocate(Revenue, 3);
AddRecognition(DateSigned, allocsBD[0]);
AddRecognition(DateSigned.AddDays(30), allocsBD[1]);
AddRecognition(DateSigned.AddDays(60), allocsBD[2]);
break;
}
}
// foreign key
private int ProductID;
// object pointer
private Product _Product;
// relationship property
protected Product Product
{
get
{
// Lazy Load
if (this._Product == null)
this._Product = Product.LoadById(this.ProductID);
return this._Product;
}
}
// Identity Map
public static IDictionary loaded = new Hashtable();
// load
Product aux = new Product();
DataSet ds = ExecuteQuery("SELECT * FROM TProducts WHERE productID=" +
productID);
p = new Product(ds.Tables[0].Rows[0]);
// save in registry
loaded[productID] = p;
return p;
}
public void Save() {
BeginTransaction();
object[] parms = new object[] {this.ProductID, this.CustomerID,
this.DateSigned, this.Revenue, this.ID};
if (this.ID != 0) {
sqlContract = "UPDATE TContracts SET productId=?, customerID=?,
dateSigned=?, revenue=? WHERE contractID=?";
ExecuteTransactedNonQuery(sqlContract, parms);
ExecuteTransactedNonQuery("DELETE FROM TRevenueRecognitions WHERE
contractID=" + this.ID);
} else {
sqlContract = "INSERT INTO TContracts(productId, customerId,
dateSigned, revenue) VALUES(?, ?, ?, ?)";
this.myID = ExecuteTransactedNonQuery(sqlContract, parms);
}
foreach (RevenueRecognition r in _RevenueRecognitions) {
string sqlRecognition = "INSERT INTO
TRevenueRecognitions(contractID, dateRecognition, amount)
VALUES(?, ?, ?)";
object parms[] = new object[] {this.ID, r.DateRecognition,
r.Amount};
ExecuteTransactedNonQuery(sqlRecognition, parms);
}
CommitTransaction();
}
Part 5.4
UI
«domain model»
«data mapper»
BLL
DAL
Database
Customer Contract
- _ID : int + «property» Product : Product
- _name : string - _ID : int
Business logic + «property» ID : int - _Customer - _CustomerID : int
- _DateSigned : DateTime
+ Customer ( )
methods only + «get» ID ( ) : int
- _ProductID : int
- _Revenue : decimal
+ «property» Customer : Customer
Product + «property» RevenueRecognitions : IList
+ «property» DateSigned : DateTime
+ «property» Type : string + «property» Revenue : decimal
- _ID : int + «property» ID : int
- _name : string
- _type : string ~ AddRecognition ( [in] recognitionDate : DateTime , [in] amount : decimal )
+ «property» ID : int + Contract ( )
+ RecognizedRevenue ( [in] asOf : DateTime ) : Money
+ Product ( ) - _Product + CalculateRevenueRecognitions ( )
+ «get» Type ( ) : string + «get» Product ( ) : Product
+ «get» ID ( ) : int ~ SetID ( [in] id : int )
~ SetProduct ( [in] prodID : int , [in] prodType : string )
IRevenueRecognitionStrategy - SetStrategy ( [in] prodType : string )
- theStrategy ~ SetProduct ( [in] prodID : int )
+ «get» Customer ( ) : Customer
+ «get» RevenueRecognitions ( ) : IList
RevenueRecognition + «get» DateSigned ( ) : DateTime
+ «get» Revenue ( ) : decimal
+ Amount : decimal
+ «get» ID ( ) : int
+ DateRecognition : DateTime
~ SetCustomer ( [in] custID : int )
+ ID : int
+ «set» Product ( [in] value : Product )
+ RevenueRecognition ( [in] id : int , [in] dt : DateTime , [in] amt : decimal ) + «set» DateSigned ( [in] value : DateTime )
+ RevenueRecognition ( [in] dt : DateTime , [in] amt : decimal ) + «set» Revenue ( [in] value : decimal ) 72
ISEP/IP
*
- _RevenueRecognitions P
public void CalculateRevenueRecognitions()
{
switch (this.Product.Type) {
case "PT":
AddRecognition(this.DateSigned, this.Revenue);
break;
case "FC":
decimal[] allocsFC = Money.Allocate(Revenue, 3);
AddRecognition(DateSigned, allocsFC[0]);
AddRecognition(DateSigned.AddDays(60), allocsFC[1]);
AddRecognition(DateSigned.AddDays(90), allocsFC[2]);
break;
case "BD":
decimal[] allocsBD = Money.Allocate(Revenue, 3);
AddRecognition(DateSigned, allocsBD[0]);
AddRecognition(DateSigned.AddDays(30), allocsBD[1]);
AddRecognition(DateSigned.AddDays(60), allocsBD[2]);
break;
}
}
Pattern GoF
Problem:
Allow the client the choice of many alternatives,
but each is complex, and you don't want to
include code for all.
Solution:
Make many implementations of the same
interface, and allow the client to select one and
give it back to you.
Pattern GoF
IRevenueRecognitionStrategy
Pattern
IdentityMap
# «property» Registry : IDictionary
+ IdentityMap ( )
DBFactory # CheckRegistry ( [in] id : int ) : object
# AddToRegistry ( [in] id : int , [in] o : object )
+ DBFactory ( ) # «get» Registry ( ) : IDictionary
+ CreateDBHelper ( ) : IDBHelper
79
DBHelper
+ «property» CurrentTransaction : IDbTransaction
- CONNSTR : string = @"Provider=..."
+ DBHelper ( )
+ BeginTransaction ( )
+ CommitTransaction ( )
+ ExecuteNonQuery ( [in] tx : IDbTransaction , [in] cmd : IDbCommand ) : int
+ ExecuteNonQuery ( [in] sql : string ) : int
IDBHelper + ExecuteQuery ( [in] sql : string ) : DataSet
+ ExecuteTransactedNonQuery ( [in] sql : string ) : int
+ ExecuteTransactedQuery ( [in] sql : string ) : DataSet
+ GetConnection ( [in] open : bool ) : IDbConnection
+ RoolbackTransaction ( )
+ «get» CurrentTransaction ( ) : IDbTransaction
+ ExecuteTransactedNonQuery ( [in] cmd : IDbCommand ) : int
+ CreateCommand ( ) : IDbCommand
+ CreateCommand ( [in] inTransaction : bool ) : IDbCommand
+ CreateParameter ( [in] name : string , [in] value : object ) : IDataParameter
+ CreateParameter ( [in] name : string , [in] tp : DbType , [in] value : object ) : IDataParameter
+ ExecuteQuery ( [in] cmd : IDbCommand ) : DataSet
: Actor1 / UI : ContractMapper : DBFactory : BaseStrategy
1 : \Form_Load\
2 : LoadAll ( )
3 : CreateDBHelper ( )
4 : \new\ : IDBHelper
5 : ExecuteQuery ( cmd )
6 : ApplyMap ( dsContractAnd
Recognitions )
7 : [currentrow.Id != current
Contract.ID] \new\ : Contract
8 : SetID ( id )
11 : CreateStrategy ( prodType , c )
12 : AddRecognition ( recognitionDate
, amount )
foreach returned
recognition 81
ISEP/IP
P
protected Contract ApplyMap(DataSet dsCNR)
{
if (dsCNR].Rows.Count < 1)
return null;
Contract c = new Contract();
c.DateSigned = (DateTime)dsCNR.Tables[0].Rows[0]["Datesigned"];
c.Revenue = (decimal)dsCNR.Tables[0].Rows[0]["Revenue"];
c.SetID( (int)dsCNR.Tables[0].Rows[0]["ID"] );
c.SetProduct( (int) dsCNR.Tables[0].Rows[0]["ProductID"],
(string) dsCNR.Tables[0].Rows[0]["ProdType"] );
c.SetCustomer( (int)dsCNR.Tables[0].Rows[0]["CustomerID"] );
foreach (DataRow r in dsCNR.Tables[0].Rows)
{
c.AddRecognition( (DateTime)r["dateRecognition"],
(decimal)r["amount"]);
}
return c;
}
public class Contract
{
// !!! to be used only by Mapper
internal void SetProduct(int prodID, string prodType)
{
_ProductID = prodID;
SetStrategy(prodType);
}
83
public abstract class BaseStrategy
{
protected Contract theContract;
public BaseStrategy(Contract c) {
theContract = c;
}
public static IRevenueRecognitionStrategy CreateStrategy(
string prodType, Contract c)
{
switch (prodType) {
case "PT": return new Strategies.PTStrategy(c);
break;
case "FC": return new Strategies.FCStrategy(c);
break;
case "BD": return new Strategies.BDStrategy(c);
break;
default:
throw new ApplicationException("invalid type");
}
return null;
}
}
: Actor1 / UI / c : Contract : IRevenueRecognitionStrategy : ContractMapper : DBFactory
1 : \btnCalc_Click\
2 : CalculateRevenueRecognitions ( )
3 : CalculateRevenueRecognitions ( )
4 : AddRecognition ( recognitionDate ,
amount )
foreach recognized
revenue
5 : Save ( c )
6 : CreateDBHelper ( )
7 : \new\
: IDBHelper
8 : BeginTransaction ( )
9 : ExecuteTransactedNonQuery ( cmd
)
10 : ExecuteTransactedNonQuery (
foreach recognized revenue cmd )
11 : CommitTransaction ( )
85
ISEP/IP
P
public void CalculateRevenueRecognitions()
{
_RevenueRecognitions.Clear();
theStrategy.CalculateRevenueRecognitions();
}
90
Pattern
92
Pattern
Problem:
You need a set of related classes but there are
several sets with different implementations
Solution:
Create a service interface, create several
implementations of those services, create a
factory class for each set of implementations,
provide the client with the correct
implementation behind the interface
Pattern GoF
Problem:
Allow functionally to be layered around an
abstraction, but still dynamically changeable.
Solution:
Combine inheritance and composition. By making
an object that both subclasses from anther class
and holds an instance of the class, can add new
behavior while referring all other behavior to the
original class.
Pattern GoF
???? ...
... Java/C#... ???
????
... Pattern ...
... Java/C#... Adapter ...
Domain model ...
output
Business
operations
http://w2ks.dei.isep.ipp.pt/psousa/GetFile.aspx?file=PoEAAWorkbench.zip
public interface IRevenueRecognition
{
Money RecognizedRevenue(int contractID, DateTime asOf);
object GetContracts();
object GetCustomers();
object GetProducts();
}
common
Complex logic
Domain Model
134
Table Module
Table Data Gateway
136
Hibernate e nHibernate
www.hibernate.org
LINQ
http://msdn.microsoft.com/en-us/netframework/aa904594.aspx
JDO
http://java.sun.com/products/jdo/
SDO
http://www.osoa.org/display/Main/Service+Data+Objects+Home
EJB 3
http://java.sun.com/products/ejb/
Apache Cayenne
http://cayenne.apache.org/
FastObjects j2
http://www.versant.net/eu_en/products/fastobjects_j2/
FastObjects.NET
http://www.versant.net/eu_en/products/fastobjects_net/
Prevayler
http://www.prevayler.org/wiki.jsp
Only in data access layer
Don’t forget Views
Balance dynamic SQL and stored procedures
Flexibility
Security
Easyest implementation for some business
logic (e.g., group operations)
138
Use parameters instead of string concatenation
DELETE is uncommon
INSERT causes no locking problem
Must be careful on UPDATE
Concurrent access
Incremental update
▪ E.g. Update quantity on hand
▪ UPDATE Products SET QtyOnHand = 10
▪ UPDATE Products SET QtyOnHand = QtyOnHand + 2
Good scalability and user-centered
availability
Optimistic Lock
Driven by example
143
Paulo Sousa
[email protected] http://linkedin.com/in/pagsousa
Paulo Sousa
[email protected]
Instituto Superior de Engenharia do Porto
Fowler, Martin. Patterns of Enterprise Application Architecture. Adisson-Wesley.
Erich Gamma, Richard Helm, Ralph Johnson, John Vissides. Design patterns : elements of
reusable object-oriented software. Adisson-Wesley.
Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal. Pattern-
oriented Software Architecture: System of Patterns.
Buschmann, F.; Henney, K. And Schmidt, D. (2007) Pattern-Oriented Software Architecture: A
Pattern Language for Distributed Computing, Volume 4. Willey.
Deepak Alur, John Crupi and Dan Malks. Core J2EE Patterns: Best Practices and Design
Strategies. Prentice Hall / Sun Microsystems Press.
http://java.sun.com/blueprints/corej2eepatterns/index.html
Enterprise Solution Patterns Using Microsoft .NET. Microsoft Press.
http://msdn.microsoft.com/architecture/patterns/default.aspx?pull=/library/en-
us/dnpatterns/html/Esp.asp
Designing Data Tier Components and Passing Data Through Tiers. Microsoft Patterns &
Practices. http://msdn.microsoft.com/library/?url=/library/en-
us/dnbda/html/BOAGag.asp?frame=true
147
GoF Design patterns (em C#)
http://www.dofactory.com/Patterns/Patterns.aspx
GoF & POSA Design patterns (em Java)
http://www.vico.org/pages/PatronsDisseny.html
Patterns of Enterprise Application architecture
http://martinfowler.com/eaaCatalog/
Core J2EE Patterns
http://www.corej2eepatterns.com