360 likes | 538 Views
Enterprise application architecture. Domain Logic Patterns. Transaction Script Domain Model Table Module Service Layer. Transaction Script. Organizes business logic by procedures where each procedure handles a single request form the presentation. TS: How It Works.
E N D
Domain Logic Patterns • Transaction Script • Domain Model • Table Module • Service Layer
Transaction Script • Organizes business logic by procedures where each procedure handles a single request form the presentation
TS: How It Works • Each business transaction corresponds to one transaction script • Business transaction: Book a hotel room • Tasks: check room availability, calculate rates, update the database – all handled in one BookARoom script. • Transaction scripts access the database directly • Don’t call any logic in the presentation layer • Organization • Each script is a procedure • Related scripts are enclosed in one class • Each script is in one class.
TS: Architecture TransactionScript businessTransaction1() businessTransaction2() businessTransaction3() Gateway sql_query= “ SELECT * FROM table 1…” sql_insert = “INSERT into tablei…” sql_update = “ UPDATE tablei …” sql_delete = “DELETE FROM …” findDataForBusinessTransaction1(sql_query) insertRecordsForBusinessTransaction1(sql_insert, items) updateRecordsForBusinessTransaction2(sql_update, items) … DB
TS: When to use it • When the domain logic is very simple • When transactions do not have a lot of overlap in functionality
Example Revenue Recognition • A contract is signed for one product • The revenue of a contract may not be recognized right away. • Different types of product may have different revenue recognition schedule • Three types of product • Word Processor: revenue recognized right away • Spreadsheet: 1/3 today, 1/3 in 60 days, 1/3 in 90 days. • Database: 1/3 today, 1/3 in 30 days, 1/3 in 60 days. 1 1 * * Product Contract RevenueRecognition Name type date _signed revenue Amount date
TS: Example RecognitionService calcRecognitions(contract#) recognizedRevenue(contract#, date) createContract(id, revenue, prod_id, date) … DatabaseGateway Sql_findContract = “ SELECT * FROM Contract WHERE id = ?” Sql_findRecogns = “select* from recog Where cid=? and date<?” Sql_insertContract = “INSERT into contract…” findContract(contract#) findRecognitionsFor(contract#, date) insertRecognition(contract#, revenue, date) … DB
Sequence Diagram: test cases :Tester :RecognitionService :DatabaseGateway :Database createContract() insertContract() INSERT into contract … calcRecognitions() insertRecognition() INSERT iintoRecog… insertRecognition() INSERT iintoRecog… insertRecognition() INSERT iintoRecog… recognizedRevenue() findRecognitionsFor() SELECT * FROM …
TS: Example class Gateway { static String findRecogns = “SELECT * FROM revenueRecognition WHERE contract = ? And date <= ?”; static String findContract = “SELECT * FROM contract c, product p WHERE c.id = ? And c.pid = p.id”; public ResultSetfindRecognitionsFor(intcontrno, Date d) { PreparedStatement s = db.prepareStatement(findRecongs); s.setInt(1, contrno); s.setDate(2, d); ResultSet result = s.executeQuery(); return result; } public ResultSetfindContract(intcontrno) { PreparedStatement s = db.prepareStatement(findContract); s.setInt(1, contrno); ResultSet result = s.executeQuery(); return result; } }
TS: Example class RecognitionService { private Gateway gw = new Gateway(); public Money recognizedRevenue(intcontrno, Date d) { Money Result = Money.dollar(0); ResultSetrs = gw.findRecognitionsFor(contrno, d); while (rs.next()) { result = result.add(rs.getBigDecimal(“amount”)); } return result; } public void calculateRevenueRecognitions(intcontrno) { ResultSetcontrs = gw.findContract(contrno); totalRevenue = contrs.getBigDecimal(“revenue”); dates = contrs.getDate(“date_signed”); type = contrs.getChar(“type”); if (type == ‘S’) { db.insertRecognition(contrno, totalRevenue/3, date); db.insertRecognition(contrno, totalRevenue/3, date+60); db.insertRecognition(contrno, totalRevenue/3, date+90); } else if (type = ‘W’) { db.insertRecognition(contrno, totalRevenue, date); } else if (type == ‘D’ { ... } ...
Domain Model • An object model of the domain that incorporates both behavior and data
DM: Revenue Recognition 1 * Contract RevenueRecognition date _signed revenue Amount date recognizedRevenue(date) calculateRecognitions() isRecognizableBy(date) * 1 Product DB Name type calcRecognitions(contrct) Three-way RecognitionStrategy * 1 RecognitionStrategy Complete RecognitionStrategy calcRecognitions(contrct)
DM: Example class RevenueRecognition { private Money amount; private Date date; public RevenueRecognition(Money amnt, Date d) {...} public Money getAmount() { return amount; } public booleanisRecognizableBy(Date date) { return this.date.before(date) || this.date.equals(date); } ... } class Contract { private List revenueRecognitions = new ArrayList(); public Money recognizedRevenue(Date date) { Money result = Money.dollar(0); Iterator it = revenueRecognitions.iterator(); while (it.hasNext()} { RevenueRecognition r = (RevenueRecognition)it.next(); if (r.isRecognizableBy(date)) result = result.add(r.getAmount()); } return result; } ...
DM: Example class RevenueRecognition { private Money amount; private Date date; public RevenueRecognition(Money amnt, Date d) {...} public Money getAmount() { return amount; } public booleanisRecognizableBy(Date date) { return this.date.before(date) || this.date.equals(date); } ... } class Contract { private List revenueRecognitions = new ArrayList(); public Money recognizedRevenue(Date date) { Money result = Money.dollar(0); Iterator it = revenueRecognitions.iterator(); while (it.hasNext()} { RevenueRecognition r = (RevenueRecognition)it.next(); if (r.isRecognizableBy(date)) result = result.add(r.getAmount()); } return result; } ...
DM: Example class Contract { private Product product; private Money amount; private Date dateSigned; private long id; public Contract(Product p, Money amnt, Date d) {...} public void addRecognition(RevenueRecognitionrr) { revenueRecognitions.add(rr); } public Date getDateSigned() { return dateSigned; } public void calcRecognitions() { product.calcRecognitions(this); } ... } interface RecognitionStrategy { public void calcRevenueRecognitions(Contract c); }
DM: Example class CompleteRecognitionStrategy implements ... { public void calcRevenueRecognitions(Contract c) { c.addRecognition(new RevenueRecognition( c.getAmount(), c.getDateSigned()); } } class ThreeWayRecognitionStrategy implements ... { private intfirstRecognitionOffset; private intsecondRecognitionOffset; public ThreeWayRecognitionStrategy(int offset1, int offset2) { this.firstRecognitionOffset = offset1; this.secondRecognitionOffset = offset2; } public void calcRevenueRecognitions(Contract c) { c.addRecognition(new RevenueRecognition( c.getAmount()/3, c.getDateSigned()); c.addRecognition(new RevenueRecognition( c.getAmount()/3, c.getDateSigned()+offset1); c.addRecognition(new RevenueRecognition( c.getAmount()/3, c.getDateSigned()+offset2); } ... }
DM: Example class Product { private String name; private RecognitionStrategyrecogStrategy; public Product(String name, RecognitionStrategyrs) { this.name = name; this.recogStrategy = rs; } public void calcRecognitions(Contract c) { recogStrategy.calcRecognitions(c); } public static Product newWordProcessor(String name) { return new Product(name, new CompleteRecognitionStrategy()); } public static Product newSpreadsheet(String name) { return new Product(name, new ThreeWayRecognitionStrategy(60, 90)); } public static Product newDatabase(String name) { return new Product(name, new ThreeWayRecognitionStrategy(30, 60)); } }
DM: Example class Tester { public static void main(String[] args) { Product word = Product.newWordProcessor(“IntelWord”); Product calc = Product.newSpreadsheet(“calc II”); Product db = Product.newDatabse(“DB IV”); Date today = System.today(); Contract c1 = new Contract(word, 300000, today); c1.calcRecognitions(); Contract c2 = new Contract(calc, 24000, today); c2.calcRecognitions(); // sequence diagram – next slide Contract c3 = new Contract(db, 540000, today); c3.calcRecognitions(); System.out.println(c1.recognizedRevenue(today + 10)); System.out.println(c2.recognizedRevenue(today + 70)); System.out.println(c3.recognizedRevenue(today + 80)); } }
DM: Sequence Diagram: c2.calcRecognitions() :Tester c2.:Contract recogStrategy:RecognitionStrategy product:Product calcRecognitions() calcRecognitions(c2) calcRecognitions(c2) Mount = getAmount() (amount/3, date) date = getDateSigned() rr1:RevenueRecognition addRecognition(rr1) (amount/3, date + 60) rr2:RevenueRecognition addRecognition(rr2) (amount/3, date + 90) rr3:RevenueRecognition addRecognition(rr3)
DM: Sequence Diagram: c2.recognizedRevenue() :Tester c2.:Contract rr[0]:RevenueRecognition rr[1]:RevenueRecognition rr[2]:RevenueRecognition recognizedRevenue(date) isRecognizableBy(date) getAmount() isRecognizableBy(date) getAmount() isRecognizableBy(date) return result
Table Module • A single instance that handles the business logic for all rows in a database table or view • Each module is responsible for all the CRUD operations on the corresponding table. • No other modules are supposed to CRUD directly on the table • Each module also includes business logic that is tightly related to the table.
TM: Architecture TableModule_1 Table_1 CRUD operations on Table_1 Business Logic related to Table_1 Attributes TableModule_2 Table_2 CRUD operations on Table_2 Business Logic related to Table_2 Attributes Database TableModule_n Table_n CRUD operations on Table_n Business Logic related to Table_n Attributes
TM: Example - Tables Contract RevenueRecognition Id: Number dateSigned: Date revenue: Number prod_id: Number (FK) Id: Number amount: Number date: Date c_id: Number (FK) Product Id: Number name: String type: String
TM: Example - Modules Contract RevenueRecognition Insert(cid, revenue, prod_id, date) calculateRecognitions(c_id) Insert(c_id, amount, date) recognizedRevenue(c_id, date) Product getProductType(prod_id) DB
TM: Sequence Diagram: calcRecognitions() :Tester :RevenueRecognition :Contract calcRecognitions(cid) :Product getContract(id) DB contract:ResultSet SELECT getProductID() getProductType(pid) SELECT getRevenue() getDateSigned() insert(cid, revenue/3, date) INSERT insert(cid, revenue/3, date+60) INSERT insert(cid, revenue/3 date+90) INSERT return result
TM: Sequence Diagram: recognizedRevenue() :Tester :RevenueRecognition :Contract recognizedRevenue(c_id, date) getRecognitions(c_id, date) DB recognitions:ResultSet SELECT getAmount() getAmount() getAmount() return result
Service Layer • Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation. • Two type of business logic • Domain logic: pure logic of the business domain • E.g., calculating revenue recognitions of a contract • Application logic: application responsibilities • E.g., notifying administrators and integrated applications, of revenue recognition calculations
TM: Example - Modules Integration Gateways Data Loader User Interfaces Service Layer Domain Model DB
SL: Architecture • Domain logic: Domain model layer • Application logic: Service layer • Service layer: • Operation Scripts – A set of classes that implement application logic but delegate to domain model classes for domain logic. • Clients interact with the operation scripts • Operation scripts for a subject area are encapsulated in a class named SubjectService.
SL: Services and Operations • Determined by the needs of clients • Derived from use case models • Data validation • CRUD operations on domain objects • Notification of people or other integrated applications • All responses must be coordinated and transacted automatically by the service layer
SL: When to Use It • When there are many different kinds of clients • When the response may involve application logic that needs to be transacted across multiple transactional resources
SL: Example • Revenue Recognition • New requirements: once revenue recognitions are calculated, it must • Email a notification to contract administrators • Publish a message to notify other integrated applications
SL: Example ApplicationService getEmailGateway(): EmailGateway getIntegrationGateway(): IntegrationGateway IntegrationGateway EmailGateway publishRevenueRecogs(contract) sendEmail(toAddr, subj, body) RecognitionService calcRevenueRecogs(contr#) recognizedRevenue(contr#, date) Domain Model Contract RevenueRecognition Product
SL: Example class RecognitionService extends ApplicationService { public void calcRevenueRecogs(contractNo) { Transaction trans = Transaction.getNewTransaction(); trans.begin(); // delegate to domain objects Contract contract = Contract.getContract(contractNo); contract.calcRecognitions(); Contract c2 = new Contract(calc, 24000, today); // interact with transactional sources getEmailGateway().sendEmail(contract.getAdminEmail(), “RE: contract revenue recognitions”, contract.getId() +”Recognitions calculated”); getIntegrationGateway().publishRevenueRecogs(contract); trans.commit(); } }
Domain Logic: Summary • Transaction Script • One script per user request/action • Good for simple, no-overlapping business logic • Domain Model • A set of interrelated objects for business logic • Good for application with complex business logic • Table Module • A module for the CRUD operations and business logic for a table in DB • Compromise between Transaction Script and Domain Model • Service Layer • Application logic is separated into a new layer from domain logic • Good for applications that have complex application logic – interacting with multiple transactional resources