Wzorce logiki dziedziny

Transkrypt

Wzorce logiki dziedziny
Wzorce logiki dziedziny
1. Wzorce logiki dziedziny
●
skrypt transakcji (Transaction Script), brama tabeli (Table Data
Gateway),
●
model dziedziny (Domain model), strategia (Strategy),
●
moduł tabeli (Table Module), zbiór rekordów (Record Set).
4. Warstwa usług
●
Domain Facade, Operation Scripts, Layer Supertype, Session
Facade.
1
Transaction Script
Pojedyncza interakcja pomiędzy programem klienckim a aplikacja
biznesową zwykle powoduje (zgodnie z logiką aplikacji) wykonanie
szeregu operacji – transakcji. Wzorzec Transaction Script
implementuje je w pojedynczej procedurze.
Przykład:
Procedura rezerwacji kabiny:
- utworzenie nowej rezerwacji w systemie,
- obciążenie karty kredytowej,
- wydrukowanie biletu.
2
Przykład
Sprzedaż ratalna:
Product
1
N
type
Contract
signed
total
1
N Installment
amount
date
Z każdą umową związany jest jeden rodzaj produktów. Każda wpłata
dotyczy określonej umowy.
Chcemy:
- znaleźć przychód na dany dzień wynikający z określonej umowy,
- tworzyć harmonogramy spłat.
3
Table Data Gateway
class InstallmentGateway ...
public ResultSet finfInstallmentFor(long cid, date d){
PreparedStatement stmt = db.prepareStatement(
"SELECT amount FROM installment WHERE" +
" con_id = ? AND date <= ?");
stmt.setLong(1, cid);
stmt.setDate(2, d);
return stmt.executeQuery();
}
Wzorzec Gateway służy do oddzielenia kodu SQL od reszty aplikacji.
Zwykle dla jednej tabeli tworzona jest jedna klasa typu Gateway.
4
Transaction Script
class InstallmentService ...
public Money getIncome(long cid, Date d){
Money m = new Money(0.0);
try{
ResultSet rs = db.findInstallmentFor(cid, d)
while(rs.next()){
m.add(new Money(rs.getBigDecimal("amount")))
}
return m;
}catch(SQLException ex){
throw new ApplicationException(ex);
}
}
Skrypt sumuje dane przekazane przez bramę – zawiera logikę
biznesową.
5
Transaction Script
Analogicznie realizujemy tworzenie harmonogramy spłat:
class InstallmentService ...
public void calculateInstallments(long cid){
try{
ResultSet rs = db.findContract(cid);
rs.next();
Date d = rs.getDate("signed");
Money total = rs.getBigDecimal("total");
String type = rs.getString("type");
if (type.equals("A")){
Money inst = total.allocate(3);
db.insertIntallment(cid, inst[0], d);
db.insertIntallment(cid, inst[1], d.addMonth(1));
db.insertIntallment(cid, inst[2], d.addMonth(2));
}else if (type.equals("B")){
Money inst = total.allocate(2);
db.insertIntallment(cid, inst[0], d.addMonth(6));
db.insertIntallment(cid, inst[1], d.addMonth(12));
}...
}catch(SQLException ex){ ... }
}
6
Transaction Script
InstallmentService
getIncome(long, Date): Money
calculateInstallments(long): void
Zalety:
- prostota w przypadku niewielkich aplikacji,
- efektywność
Wady:
- powtórzenia kodu,
7
Domain Model
Przychód na dany dzień wynikający z określonej umowy jest obliczany
w klasie Contract... .
class Contract ...
private List<Installment> installments;
...
public Money getIncome(Date d){
Money m = new Money(0.0);
for (Iterator<Installment> it = installments.iterator();
it.hasNext(); ){
Installment inst = it.next();
if (inst.getDate().before(d)){
m.add(inst.getAmount());
}
}
return m;
}
}
8
Domain Model
Tworzenie odpowiednich obiektów Installment jest realizowane przy
współpracy kilku klas.
class Contract ...
private Product product;
private Money total;
private Date signed;
...
public Contract(Product p, Modey m, Date d){
this.product = p;
this.total = m;
this.signed = d;
}
9
Domain Model
class Product ...
private InstallmentStrategy strategy;
...
public Product(..., InstallmentStrategy s){
...
this.strategy = s;
}
public static Product newTypeA(...){
return new Product(..., new TypeAStrategy());
}
public static Product newTypeB(...){
return new Product(..., new TypeBStrategy());
}
Dodatkowo wykorzystamy wzorzec Strategii (Strategy)..
10
Domain Model
class InstallmentStrategy{
abstract void calculateInstallments(Contract c);
}
class TypeAStrategy{
void calculateInstallments(Contract c){
Money inst = c.getTotal.allocate(3);
Date d = c.getSigned();
c.addInstallment(inst[0], d);
c.addInstallment(inst[1], d.addMonth(1));
c.addInstallment(inst[2], d.addMonth(2));
}
}
class TypeBStrategy{
void calculateInstallments(Contract c){
Money inst = c.getTotal.allocate(2);
Date d = c.getSigned();
c.addInstallment(inst[0], d.addMonth(6));
c.addInstallment(inst[1], d.addMonth(12));
}
}
Strategie umożliwiają łatwą rozbudowę aplikacji o nowe reguły
biznesowe.
11
Domain Model
class Product ...
public void calculateInstallments(Contract c){
this.strategy.calculateInstallments();
}
class Contract ...
public void calculateInstallments(){
this.product.calculateInstallments(this) ;
}
Przekazujemy zlecenie do obiektu, który jest najbardziej kompetentny
do obsługi. Watro zwrócić uwagę na brak instrukcji warunkowych.
Logika aplikacji jest wpisana w strukturę obiektów.
12
Domain Model
Contract
...
*
getIncome(Date): Money
calculateInstallments(): void
Product
1
calculateInstallments(Contact): void
*
1
InstallmentStrategy
calculateInstallments(Contract): void
TypeAStrategy
calculateInstallments(Contract): void
TypeBStrategy
calculateInstallments(Contract): void
13
Table Module
Problemem Domain Model jest implementacja interfejsu relacyjnej
bazy danych. We wzorcu Table Module logika dziedziny jest
umieszczona w klasach odpowiadających poszczególnym tabelom
w bazie danych.
Podstawowa różnica względem Domain Model polega na tym, że
obsługa wielu rekordów w bazie danych (egzemplarzy) jest
realizowana przez jeden obiekt.
14
Table Module
Contract
...
getIncome(Date)
Product
getType(id)
Installment
insert(id, amount, date)
15
FilteredRowSet
W Javie najodpowiedniejszym narzędziem umożliwiającym dostęp do
danych we wzorcu TableModule jest interfejs
javax.sql.rowset.FilteredRowSet:
FilteredRowSet frs = new FilteredRowSetImpl();
frs.populate(rs);
Range name = new Range("From", "To", "column");
frs.setFilter(name);
frs.next() // to co zostanie zwrócone zależy od implementacji
klasy Range()
Filtr jest tworzony w oparciu o implementacje interfejsu
javax.sql.rowset.Predicate.
16
Predicate
public class Range implements Predicate {
private Object form, to;
private String column;
public Range(Object f, Object t, String s) {
this.from = f;
this.to = t;
this.column = s;
}
public boolean evaluate(RowSet rs) {
boolean b1, b2;
}
}
if ((rs.getObject(this.column) >= this.from) &&
(rs.getObject(this.column) <= this.to)){
return true; // spelnia warunki filtra
} else {
return false;
}
17
Table Module
Klasa Contract zarządza wszystkimi operacjami wykonywanymi na
wszystkich kontraktach.
class Contract....
private Rowset rows;
public Contract(RowSet rs){
this.rows = rs;
}
public ResultSet findContract(int cid){
FilteredRowSet frs = new FilteredRowSetImpl();
frs.populate(rs);
RSFilter filter = new RSFilter(cid, "con_id");
frs.setFilter(name);
return frs;
}
18
Table Module
Implementacja poszczególnych operacji jest bardzo podobna do tej ze
wzorca TransactionScript.
}
public void calculateInstallments(long cid){
try{
ResultSet rs = this.findContract(cid);
rs.next();
Date d = rs.getDate("signed");
Money total = rs.getBigDecimal("total");
String type = rs.getString("type");
if (type.equals("A")){
...
}
}catch(SQLException ex){
throw new ApplicationException(ex);
}
}
19
Porównanie wzorców logiki
dziedziny
Transaction Script
Table Module
nakład pracy
del
o
M
ain
m
o
D
złożoność
20
Service Layer
Zwykle logikę biznesową dzieli się na dwa rodzaje:
●
logikę dziedziny – operacje wyłącznie na dziedzinie problemu (np.
obliczanie rat),
●
logikę aplikacji (pracy) – funkcje aplikacji (logowanie, przesyłanie
wiadomości o zmianach w dziedzinie itp.).
W przypadku Domain Model obie funkcje są realizowane przez klasy
obiektów dziedziny. Powoduje to brak możliwości użycia tych
obiektów w innych aplikacjach (z inną logiką aplikacji) oraz problemy
przy ewentualnych zmianach logiki aplikacji. Z tego powodu warto
rozdzielić oba rodzaje logiki biznesowej i umieścić je w nowej
warstwie – warstwie usług.
21
Service Layer
interfejsy
użytkownika
bramy
integracyjne
import
danych
warstwa usług
model dziedziny
warstwa źródła danych
22
Service Layer
Sposoby implementacji:
●
fasada dziedziny (domain facade) – logika biznesowa w całości
pozostaje w modelu dziedziny. Warstwa usług wyznacza zbiór
operacji, które mogą być używane przez warstwy klienckie.
●
skrypty operacji (operation scripts) – zbiór klas bezpośrednio
implementujących logikę aplikacji. Logika dziedziny jest realizowana
przez hermetyczne klasy obiektów dziedziny. Zbiór klas skryptów
operacji zwykle korzysta ze wzorca Layer Supertype okreslającego
zakres funkcji oraz wspólne zachowania.
23
Layer supertype
Wzorzec polega na wprowadzeniu klasy bazowej dla wszystkich klas
danej warstwy.
class DomainObject {
private long id;
...
public long getId(){
return this.id;
}
}
public void setId(long l){
this.id = l;
}
24
Service Layer a Java
Najczęściej rolę warstwy Service Layer pełnią bezstanowe
komponenty sesysjne wyposażone w interfejs lokalny.
Podobnym wzorcem dla środowiska JEE jest wzorzec Session Facade,
jednak jego podstawową funkcją jest poprawa wydajności poprzez
osłonięcie komponentów encyjnych przed nadmierną ilością wywołań
(EJB 2.0). Service Layer dzieli implementację aby zredukować
powtórzenia kodu i umożliwić powtórne użycie obiektów dziedziny.
25
Podsumowanie
Podstawowe wzorce logiki dziedziny to Transaction Script i Domain
Model. Wzorzec Table Module można stosować, gdy język
programowania w naturalny sposób dostarcza implementacji wzorca
Record Set.
Aby nie umieszczać logiki aplikacji w implementacji dziedziny
wprowadzamy dodatkową warstwę - stosujemy wzorzec Service
Layer.
26

Podobne dokumenty