UP - fáze rozpracování II (návrh) J. Zendulka (s využitím obrázků z knihy C.Larmana a L.A.Maciaszka)
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
2
Vliv artefaktů UP Sample UP Artifact Relationships Domain Model
Business Modeling
Requirements
*
*
Use-Case Model
Supplementary Specification
Vision
Glossary
The logical architecture is influenced by the constraints and non-functional requirements captured in the Supp. Spec. Design Model package diagrams of the logical architecture (a static view)
UI Domain Tech Services
: Register Design
interaction diagrams (a dynamic view)
: ProductCatalog
enterItem (itemID, quantity) spec = getProductSpec( itemID )
Register class diagrams (a static view)
... makeNewSale() enterItem(...) ...
© J.Zendulka 2006 - 8
ProductCatalog 1
1
... getProductSpec(...) ...
UP - fáze rozpracování II (návrh)
3
Logická architektura
Logická architektura – organizace tříd do balíčků (jmenných prostorů), podsystémů, vrstev. Neříká nic o nasazení do různých prostředí, na různé počítače atd. (architektura nasazení (deployment architecture)).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
4
Vrstvy
Seskupení tříd, balíčků, podsystémů, které souvisejí z hlediska zodpovědnosti za nějaký významný aspekt systému. Organizovány hierarchicky, vyšší využívá služeb nižší vrstvy. Typické vrstvy: uživatelské
rozhraní aplikační logika a objekty domény technické služby (přístup k databázi, záznam chyb, …) © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
5
Vrstvené architektury Striktní (uzavřená) vrstvená architektura vyšší vrstva může používat jen bezprostředně nižší vrstvu. Uvolněná (otevřená) vrstvená architektura - vyšší vrstva může používat několik nižších vrstvev. Organizace architektury do vrstev je v současnosti velmi běžné.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
6
Softwarová architektura Soubor významných rozhodnutí o organizaci SW systému, výběru strukturních prvků a jejich rozhraní, pomocí nichž je systém sestaven, společně s jejich chováním specifikovaným spoluprací těchto prvků, seskupení do postupně větších podsystémů a architektonický styl, který řídí tuto organizaci. Organizace „ve velkém“
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
7
Modelování logické architektury v UML – diagram balíčků UI
Domain
Swing
Sales
Web
UI UI::Swing
UI::Web
Swing
Web
Domain::Sales
Domain Sales
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
8
Návrh s vrstvami
Organizace do vrstev s různou zodpovědností, s jasným oddělením toho, co řeší („concern“), tak, že nižší vrstvy poskytují obecnější služby nižší úrovně , zatímco vyšší vrstvy jsou aplikačně specifičtější. Spolupráce a vazba (reprezentovaná závislostmi) je od vyšších vrstev k nižším, ne naopak.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
9
Návrh s vrstvami – řešené problémy Šíření změn v systému. Provázání aplikační logiky a uživatelského rozhraní. Obecné technické služby jsou provázány s aplikačně specifičtější logikou Vysoké provázání částí řešících různé věci → je obtížné rozdělení práce vývojářům.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
10
Typické vrstvy architektury IS handles presentation layer requests workflow session state window/page transitions consolidation/transformation of disparate data for presentation handles application layer requests implementation of domain rules domain services (POS, Inventory) - services may be used by just one application, but there is also the possibility of multi-application services
very general low-level business services used in many business domains CurrencyConverter
(relatively) high-level technical services and frameworks Persistence, Security
low-level technical services, utilities, and frameworks data structures, threads, math, file, DB, and network I/O
UI (AKA Presentation, View) more app specific
Application (AKA Workflow, Process, Mediation, App Controller)
dependency
GUI windows reports speech interface HTML, XML, XSLT, JSP, Javascript, ...
Domain (AKA Business, Application Logic, Model)
Business Infrastructure (AKA Low-level Business Services)
Technical Services (AKA Technical Infrastructure, High-level Technical Services)
Foundation (AKA Core Services, Base Services, Low-level Technical Services/Infrastructure) width implies range of applicability
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
11
Návrh s vrstvami – výhody
Oddělení věcí, které vrstvy řeší, oddělení aplikačně specifických od obecných služeb → redukce provázanosti a zvýšení koheze, zvýšení potenciálního opakovaného použití a srozumitelnosti. Komplexnost je zapouzdřena ve vrstvách. Některé vrstvy mohou být nahrazeny novou implementací. Některé vrstvy mohou být distribuované. Jsou vytvořeny lepší podmínky pro vývoj v týmu.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
12
Objekty domény
Jak navrhnout OO aplikační logiku? Jedna
třída zahrnující všechny potřebné metody. Třídy odpovídající reálné doméně s odpovídající informací a operacemi → (SW) objekty domény.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
13
Vztah modelu domény a modelu návrhu UP Domain Model Stakeholder's view of the noteworthy concepts in the domain. A Payment in the Domain Model is a concept, but a Payment in the Design Model is a software class. They are not the same thing, but the former inspired the naming and definition of the latter.
Sale
Payment
1
Pays-for
1 date time
amount inspires objects and names in
This reduces the representational gap.
Sale This is one of the big ideas in object technology.
Payment amount: Money
1
Pays-for
getBalance(): Money
1
date: Date startTime: Time getTotal(): Money ...
UP Design Model The object-oriented developer has taken inspiration from the real world domain in creating software classes. Therefore, the representational gap between how stakeholders conceive the domain, and its representation in software, has been lowered.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
14
Vrstvy a sekce Vrstva architektury – reprezentuje vertikální řezy. Sekce – reprezentují horizontální dělení relativně paralelních podsystémů. Pozn.:
1.
Vztahy podsystémů: a) b)
2.
klient-server, sobě rovný (peer-to-peer)
Vztah označení „layer“ a „tier“
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
15
Příklad vrstvené architektury aplikace grafika okna řízení uživatelského grafika obrazovky rozhraní grafika bodu
simulační knihovna
operační systém HW
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
16
Příklad architektury Windows NT Win16
MS-DOS
NTVDM
POSIX subsystem
Win32 subsystem
OS/2 subsystem
Security subsystem
User mode Kernel mode Executive Services System Services I/O Manager Cache manager File System drivers
Security Local Virtual Object Process Reference Procedure Memory Manager Manager Monitor Call Facility Manager
Network drivers Hardware Device Drivers
Microkernel
Window Manager (WIN32K.SYS)
Graphics Device Drivers
Hardware Abstraction Layer (HAL)
Hardware
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
17
Příklad vrstvené architektury v UML Domain
POS
Inventory
Tax
Security
Logging
Vertical Layers Technical Services Persistence
Horizontal Partitions
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
18
Zásada: Nezobrazuj externí zdroje a služby Worse mixes logical and deployment views
Better a logical view Domain(s)
Domain(s)
POS
Technical Services
Technical Services
Foundation
MySQL Inventory
Inventory
a logical representation of the need for data or services related to these subdomains, abstracting implementation decisions such as a database.
Persistence
«component» Novell LDAP
Naming and Directory Services
Web AppFramework
Foundation
UML notation: A UML component, or replaceable, modular part of the physical system UML notation: A physical database in the UML.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
19
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
20
Závislost Balíček (třída) A závisí na balíčku B jestliže si změny v balíčku B mohou vynutit změny v balíčku A. Klíčová z pohledu zajištění podporovatelnosti (supportability), tj. udržovatelnosti, srozumitelnosti a škálovatelnosti. Závislost tříd → závislost balíčků → závislost vrstev
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
21
Závislosti tříd <
> L ayer 1 Package B
Package A
Class X
P ac ka ge A d ep en ds on P ac ka ge B b ec au se Cl as s X de pe nd s o n Cla ss Y
Class Y
Layer 1 depends on Layer 2 because Class X depends on Class Z
Package C
<> Layer 2 P acka ge D
Class Z
Package E
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
22
Zdroje závislostí Dědění Asociace Volání operace Parametr operace …
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
23
Závislost třídy Test na Object zjistitelná v době překladu Test
Object 1
doTest()
public void doTest(){ Object a = new A(); ... a.wait(); ... }
© J.Zendulka 2006 - 8
wait()
A do1() do2()
UP - fáze rozpracování II (návrh)
24
Závislosti z asociací a volání control
p ubl ic cla ss EOu tMessa ge { EE mp lo yee emp; p ubl ic v oid d o2() { emp .do 3(); } }
CActioner do1() 0..1 public class CActioner { EEmployee emp; public void do1() { emp.do3(); } }
entity Act Emp
EOut Message
0..1
do2() 0..n
OutEmp
EEmployee do3() © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
0..n
25
Závislosti vrstev Nižší vrstvy by měly být stabilní.
Package A
<> L ayer 2
Package C
<> L ayer 1
Package B
Package D Layer 1 depends on Layer 2
Package E
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
26
Cykly mezi balíčky Package A
Package C
© J.Zendulka 2006 - 8
Package B
Package D
UP - fáze rozpracování II (návrh)
Package E
27
Odstranění cyklů mezi balíčky Package A
circularly-dependable
Package B
Package A2
elements of Package A extracted into Package A2
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
28
Odstranění cyklů použitím rozhraní (1) <> presentation PPrimaryWindow do2()
PDialogBox do3()
pu blic class PDial ogBox { CActione r acti oner; public vo id do3() { actioner.do4(); } }
© J.Zendulka 2006 - 8
<> control CInit do1()
public class CInit { PPrimaryWindow window; public void do1() { window.do2(); } }
CActioner do4()
public class CActioner{ public void do4() { //perform some actions } }
UP - fáze rozpracování II (návrh)
29
Odstranění cyklů použitím rozhraní (2) public class PPri maryWindow im plem ents control.ICPresenter { public void do2() { //im plem entation code } }
publ ic interface PController { publ ic void do2(); }
public class CInit { ICPresenter presenter; public void do1(){ presenter.do2(); } }
<> control
<> presentation PPrimaryWindow
ICPresenter do2()
<<uses>>
CInit do1()
do2()
PDialogBox do3()
© J.Zendulka 2006 - 8
CActioner do4() UP - fáze rozpracování II (návrh)
30
Zásada: Princip oddělení modelu a pohledu Nevytvářet vazbu objektů vnitřních vrstev (ne-UI) na objekty uživatelského rozhraní (UI) (např. třída Sale má referenci na JFrame ze Java Swing). Tj. závislost Sale na JFrame. Nevkládat aplikační logiku do operací tříd UI (např. výpočet daně), ale delegovat požadavky ne-UI objektům.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
31
Zpracování asynchronních událostí
Použitím návrhového vzoru Observer
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
32
Příklad z případové studie (1) Goal: When the total of the sale changes, refresh the display with the new value
Sale total ... setTotal( newTotal ) ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
33
Příklad z případové studie (2) {
{
for each PropertyListener pl in propertyListeners pl.onPropertyEvent( this, name, value );
propertyListeners.add( lis ); }
}
Sale addPropertyListener( PropertyListener lis ) publishPropertyEvent( name, value ) setTotal( Money newTotal ) ... { total = newTotal; publishPropertyEvent( "sale.total", total ); } javax.swing.JFrame ... setTitle() setVisible() ...
propertyListeners
*
«interface» PropertyListener onPropertyEvent( source, name, value )
{ if ( name.equals("sale.total") ) saleTextField.setText( value.toString() ); } SaleFrame1 onPropertyEvent( source, name, value )
{
initialize( Sale sale ) ...
}
© J.Zendulka 2006 - 8
sale.addPropertyListener( this ) ...
UP - fáze rozpracování II (návrh)
34
Vztah SSD, systémových operací a vrstev SSD ukazuje systémové operace. Kde se provedou? V dobře navržené vrstvené architektuře delegují objekty UI požadavek na zpracování vrstvě domény.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
35
Systémové operace v SSD a ve vrstvách UI Swing
:System : Cashier
...
ProcessSale Frame
makeNewSale() enterItem() endSale()
makeNewSale() : Cashier enterItem(id, quantity) makeNewSale() enterItem() endSale()
description, total Domain endSale()
...
Register makeNewSale() enterItem() ...
the system operations handled by the system in an SSD represent the operation calls on the Application or Domain layer from the UI layer
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
36
Logická architektura NextGen POS pro 1.iteraci UI
Swing
not the Java Swing libraries, but our GUI classes based on Swing
Web
Domain
Sales
Payments
Taxes
Logging
RulesEngine
Technical Services
Persistence
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
37
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
38
MVC – Model-View-Controler (1) Application Program
View Database and Web Services
Model
Persistent Data
Controller
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
39
MVC – Model-View-Controller (2)
Model – odpovídá vrstvě domény, obsahuje objekty domény, přidává k datům aplikační logiku (např. výpočet sumy prodeje u třídy Sale). View – zodpovědný za prezentaci modelu (objekty UI, dynamické HTML stránky). Controler – zpracovává a reaguje na události (typicky akce uživatele), může měnit stav objektů balíčků Model i View.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
40
Architektura PCMEF (Maciaszek) Core J2EE tiers
PCMEF layers <> presentation
Client Tier applets, apps user interaction, UI presentation
Core J2EE patterns
Presentation Tier
<> control
servlets, JSP session management, content management, format and delivery
Business Tier
<> domain
EJB business logic, transactions
Integration Tier
entity
mediator
JDBC, JMS, Connectors, Legacy resource adapters, external systems, rules engines, workflow
Resource Tier Databases, external systems resources, data and external services
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
<> foundation
41
Principy architektury PCMEF DDP - Downward Dependency Principle UNP - Upward Notification Principle NCP - Neighbor Communication Principle EAP - Explicit Association Principle CEP - Cycle Elimination Principle CNP - Class Naming Principle APP - Acquaintance Package Principle
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
42
Význam principů PCMEF
CNP – konvence pro pojmenování (jmého začíná písmenem vrstvy, např. EEmployee). NCP – komunikace pouze se sousední vrstvou. EAP – komunikace objektů je „vizualizována“ prostřednictvím asociací. DDP – vyšší vrstvy závisí jen na nižších. CEP – cykly mezi vrstvami jsou vyloučeny (použitím rozhraní nebo vytvořením speciálního balíčku). APP – vytvoření speciální vrstvy obsahující rozhraní pro složitější komunikaci objektů ve vrstvách. UNP – oznamování ve směru zdola nahoru mechanismem zpracování asynchronních událostí.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
43
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
44
Způsoby návrhu Přímé kódování – návrh prováděn při programování, užitečné s nástrojem podporujícím refaktorizaci. Namodelování, pak kódování. Pouze modelování – MDA, nikdy zcela automatické, vždy je potřeba připojit nějaký kód.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
45
Agilní modelování a CASE nástroje
Modely v podobě náčrtků na tabuli, snímání kamerou a tisk, Souběžné vytváření několika modelů (např. interakce a tříd) … viz http://www.agilemodeling.com/ CASE nástroje s vazbou na integrovaná vývojová prostředí (IDE) (Eclipse, Visual Studio, JDeveloper, …), žádoucí podpora reverzního inženýrství.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
46
Kolik času strávit modelováním Larman: Pro iteraci v trvání tří týdnů několik hodin, max. 1 den na začátku iterace, pak kódování inspirované modely. Podstatná je schopnost uvažovat a navrhovat objektově a schopnost aplikovat osvědčené praktiky OO návrhu. Důležité otázky OO návrhu: Jaké jseo zodpovědnosti třídy/objektu a s kým spolupracuje.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
47
CRC štítky
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
48
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
49
Základní diagramy OO návrhu Diagramy interakce – interakce objektů zasíláním zpráv (dynamický model). Diagram tříd – statická struktura tvořená třídami a rozhraními (statický model).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
50
Diagram sekvence – modelování singletonu 1
: Register
: Store
doX
the ‘1’ implies this is a Singleton, and accessed via the Singleton pattern
doA
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
51
Diagram sekvence – modelování návratové hodnoty : Register
: Sale
doX d1 = getDate getDate aDate
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
52
Diagram sekvence – vytvoření objektu : Register
note that newly created objects are placed at their creation "height"
: Sale
makePayment(cashTendered) create(cashTendered)
: Payment
authorize
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
53
Diagram sekvence – zrušení objektu : Sale create(cashTendered)
: Payment
... «destroy»
© J.Zendulka 2006 - 8
X
UP - fáze rozpracování II (návrh)
the «destroy» stereotyped message, with the large X and short lifeline indicates explicit object destruction
54
Diagram sekvence – volání operace třídy message to class, or a static method call :Foo
«metaclass» Calendar
doX
locales = getAvailableLocales public class Foo { public void doX() { // static method call on class Calendar Locale[] locales = Calendar.getAvailableLocales(); // … } // … } © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
55
Diagram sekvence –polymorfismus Payment {abstract} Payment is an abstract superclass, with concrete subclasses that implement the polymorphic authorize operation
authorize() {abstract} ...
CreditPayment
DebitPayment
authorize() ...
authorize() ...
object in role of abstract superclass
polymorphic message
:Register
:Payment {abstract}
doX authorize
:DebitPayment
stop at this point – don’t show any further details for this message
:Foo
authorize
:CreditPayment
:Bar
authorize doA
doX
doB
separate diagrams for each polymorphic concrete case
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
56
Diagram sekvence – aktivní třída a stick arrow in UML implies an asynchronous call a filled arrow is the more common synchronous call
active object
System : Class
:ClockStarter
In Java, for example, an asynchronous call may occur as follows: startClock
// Clock implements the Runnable interface Thread t = new Thread( new Clock() ); t.start();
create
the asynchronous start call always invokes the run method on the Runnable (Clock) object to simplify the UML diagram, the Thread object and the start message may be avoided (they are standard “overhead”); instead, the essential detail of the Clock creation and the run message imply the asynchronous call
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
:Clock
run runFinalization
57
Diagram komunikace – polymorfismus polymorphic message
doX
:Register
stop at this point – don’t show any further details for this message
authorize
:Payment {abstract}
authorize
:DebitPayment
object in role of abstract superclass
authorize doA doB
doX :Foo
:CreditPayment
:Bar
separate diagrams for each polymorphic concrete case
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
58
Diagram komunikace – aktivní třída startClock 3: runFinalization :ClockStarter 1: create
System : Class
asynchronous message
2: run :Clock
© J.Zendulka 2006 - 8
active object
UP - fáze rozpracování II (návrh)
59
Diagram tříd – singleton, vlastnosti třídy 1 ServicesFactory UML notation: in a class box, an underlined attribute or method indicates a static (class level) member, rather than an instance member
instance : ServicesFactory accountingAdapter : IAccountingAdapter inventoryAdapter : IInventoryAdapter taxCalculatorAdapter : ITaxCalculatorAdapter
UML notation: this '1' can optionally be used to indicate that only one instance will be created (a singleton)
getInstance() : ServicesFactory getAccountingAdapter() : IAccountingAdapter getInventoryAdapter() : IInventoryAdapter getTaxCalculatorAdapter() : ITaxCalculatorAdapter ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
60
Diagram tříd – aktivní třída active class «interface» Runnable run()
© J.Zendulka 2006 - 8
Clock ... run() ...
UP - fáze rozpracování II (návrh)
61
Vztah diagramů interakce a diagramu tříd : Register
: Sale
makePayment(cashTendered) makePayment(cashTendered)
messages in interaction diagrams indicate operations in the class diagrams
Register ... makePayment(…) ...
© J.Zendulka 2006 - 8
Sale 1 currentSale
classes identified in the interaction diagrams are declared in the class diagrams
... makePayment(…) ...
UP - fáze rozpracování II (návrh)
62
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
63
Podstata OO návrhu Nalézt třídy a interakci jejich objektů, které budou realizovat chování reprezentované případy použití při respektování omezení daných nefunkčními požadavky. Pro OO návrh je kritická znalost a schopnost aplikovat principy návrhu (ne znalost UML nebo konkrétních technologií).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
64
Vstupy OO návrhu Specifikace případů použití Doplňující specifikace Systémové diagramy sekvence (SSD) Kontrakty operací Slovník Model domény
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
65
Výstupy OO návrhu Sample UP Artifact Relationships Domain Model Sale
Business Modeling
Sales LineItem
1..*
1
date ...
... ...
quantity
Use-Case Model Process Sale Process Sale
use case names
Cashier
Requirements
Use Case Diagram
starting events to design for, and detailed postcondition to satisfy
Design
non-functional requirements
functional requirements that must be realized by the objects
Use Case Text system events
ideas for the postconditions inspiration for names of some software domain objects
Supplementary Specification
1. Customer arrives ... 2. ... 3. Cashier enters item identifier.
domain rules
: System Glossary Operation: enterItem(…) Post-conditions: -...
: Cashier
system operations
make NewSale() enterItem (id, quantity)
item details, formats, validation
System Sequence Diagrams
Operation Contracts
Design Model
: Register
: ProductCatalog
: Sale
enterItem (itemID, quantity) d = getProductDescription(itemID) addLineItem( d, quantity ) Register
ProductCatalog
... makeNewSale() enterItem(...) ...
© J.Zendulka 2006 - 8
...
*
1
getProductDescription(...) ...
UP - fáze rozpracování II (návrh)
66
Odpovědnosti (1) Jde o oblíbený způsob uvažování o návrhu tříd, ale i větších celků (viz vrstvy architektury). Odpovědnost za činnost:
dělání
něčeho – vytvoření objektů, výpočet něčeho, … spuštění nějaké akce u jiných objektů řízení a koordinace akcí jiných objektů
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
67
Odpovědnosti (2)
Odpovědnost za vědomost: privátních
zapouzdřených dat souvisejících objektů věcí, které může odvodit nebo spočítat
Př) Třída Sale je zodpovědná za vytvoření SalesLineItems a znalost celkové částky. Odpovědnosti jsou implementovány pomocí metod a spolupráce s jinými metodami a objekty.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
68
Návrh řízený odpovědností Způsob návrhu založený na uvažování o zodpovědnostech a spolupráci, jejich přiřazování třídám. Hledání množiny spolupracujících zodpovědných objektů které zajistí splnění cílů návrhu. Principy GRASP (General Responsibility Assignment Software Patterns - Larman) – učební pomůcka pro OO návrh založený na zodpovědnostech.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
69
Vztah zodpovědností a UML diagramů : Sale
makePayment(cashTendered) create(cashTendered)
: Payment
abstract, implies Sale objects have a responsibility to create Payments
Při kreslení diagramu interakce přiřazujeme zodpovědnosti.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
70
Principy GRASP Tvůrce (Creator) Informační expert (Information Expert) Nízká vazba (Low Coupling) Řadič (Controller) Vysoká koheze (High Cohesion) Polymorfismus (Polymorphism) Pouhá konstrukce (Pure Fabrication) Nepřímost (Indirection) Chráněné změny (Protected Variation)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
71
Creator Problém: Kdo vytváří objekty? Řešení: Přiřaď třídě B zodpovědnost za vytváření instancí třídy A, pokud platí některá z následujících podmínek:
• B obsahuje A • B agreguje A • B má inicializační data pro A
© J.Zendulka 2006 - 8
• B zaznamenává A • B hodně užívá A
UP - fáze rozpracování II (návrh)
72
Př) Kdo vytváří instance SalesLineItem? Sale time 1 Contains 1..* Sales LineItem
*
Described-by
1
Product Description description price itemID
quantity
: Register
: Sale
makeLineItem(quantity) create(quantity)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
: SalesLineItem
73
Creator – kdy nepoužít, přínos Jsou-li speciální požadavky, které činí vytváření složité (recyklace instancí kvůli výkonnosti, podmíněné vytváření z rodiny podobných tříd atd.), pak raději použít návrhový vzor Factory, resp. Abstract Factory. Přínos: Nezvyšuje vazbu, třída tvůrce velmi pravděpodobně již závisí na vytvářené třídě díky asociaci či zanoření.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
74
Information Expert Problém: Kdo má za co zodpovídat? (Základní princip OO návrhu a přiřazení zodpovědností.) Řešení: Přiřaď zodpovědnost informačnímu expertovi - třídě, která má informace nezbytné ke splnění zodpovědnosti.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
75
Př) Kdo zodpovědný za celkovou částku? (1) Sale time 1 Contains 1..* Sales LineItem
*
Described-by
1
description price itemID
quantity
t = getTotal
Product Description
Sale
:Sale time ... New method
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
getTotal() 76
Př) Kdo zodpovědný za celkovou částku? (2) this notation will imply we are iterating over all elements of a collection
Sale time ...
t = getTotal
: Sale
1 *: st = getSubtotal
lineItems[ i ] : SalesLineItem
getTotal()
SalesLineItem quantity New method
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
getSubtotal()
77
Př) Kdo zodpovědný za celkovou částku? (3) Sale time ... t = getTotal
: Sale
1 *: st = getSubtotal
lineItems[ i ] : SalesLineItem
1.1: p := getPrice()
getTotal()
SalesLineItem quantity
:Product Description
getSubtotal() Product Description description price itemID
New method
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
getPrice() 78
Information Expert – kdy nepoužít, přínos Někdy by použití mohlo mít nežádoucí dopad na vazbu, propojení a duplikaci. Např. ukládání info o prodeji do DB (Sale?, totéž pro každou třídu domény?) Přínos: Obvykle vede na nízkou vazbu a vysokou kohezi.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
79
Low coupling Problém: Jak redukovat vliv změn Řešení: Přiřaď zodpovědnost tak, aby nezbytná vazba byla nízká. Použij tento princip pro vyhodnocování alternativ.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
80
Př) Kdo zodpovědný za vytváření instance Payment a její spojení se Sale? (1)
Předpokládejme existenci tříd Payment, Register a Sale. makePayment()
: Register
1: create()
2: addPayment(p)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
p : Payment
:Sale
81
Př) Kdo zodpovědný za vytváření instance Payment a její spojení se Sale? (2) makePayment()
: Register
1: makePayment()
:Sale
1.1. create()
:Payment
Která varianta je lepší z pohledu nižší vazby?
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
82
Low Coupling – kdy nepoužít, přínos Silnější vazba na stabilní a běžně používané prvky (např. knihovny Javy) není problémem. Přínos: Obvykle vede na nízkou vazbu a vysokou kohezi.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
83
Controller
Problém: Který první objekt za vrstvou UI dostává a koordinuje (řídí) operaci systému? Řešení: Přiřaď zodpovědnost objektu, který reprezentuje jednu z následujících možností: 1.
2.
Reprezentuje celý systém, „kořenový objekt“ nebo zařízení, v němž SW běží, nebo hlavní podsystém (varianty tzv. „facade controller“). Reprezentuje scénář případu použití, v jehož rámci se systémová událost vyskytuje (tzv. „use case/session controller“).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
84
Př) Která třída by měla být řadičem pro enterItem? (1)
System endSale() enterItem() makeNewSale() makePayment() ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
85
Př) Která třída by měla být řadičem pro enterItem? (2) presses button
: Cashier actionPerformed( actionEvent )
UI Layer
:SaleJFrame system operation message enterItem(itemID, qty)
Domain Layer
: ???
Which class of object should be responsible for receiving this system event message? It is sometimes called the controller or coordinator. It does not normally do the work, but delegates it to other objects. The controller is a kind of "facade" onto the domain layer from the interface layer.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
86
Př) Která třída by měla být řadičem pro enterItem? (3)
Možnosti dle principu Controller: Register/POSSystem ProcessSaleHandler/ProcessSaleSession enterItem(id, quantity)
enterItem(id, quantity)
© J.Zendulka 2006 - 8
:Register
:ProcessSaleHandler
UP - fáze rozpracování II (návrh)
87
Př) Která třída by měla být řadičem pro enterItem? (3)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
88
Př) Která třída by měla být řadičem pro enterItem? (4)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
89
Controller – doporučení
Řadič by neměl dělat mnoho, spíše deleguje a řídí a koordinuje systémovou operaci. První varianta je vhodná, není-li mnoho systémových operací, resp. nelze-li přesměrovat alternativním řadičům. Řadiče pro případy použití je navíc vhodné použít tehdy, když by jediný řadič vedl na návrh s nízkou kohezí nebo vysokou vazbou. Systémové operace by měly být řešeny ve vrstvě aplikační logiky nebo domény, nikoliv objekty vrstvy UI.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
90
Vrstva UI nezpracovává systémové události - OK
presses button
: Cashier actionPerformed( actionEvent )
UI Layer
system operation message
:SaleJFrame
1: enterItem(itemID, qty)
controller
Domain Layer © J.Zendulka 2006 - 8
:Register
1.1: makeLineItem(itemID, qty)
UP - fáze rozpracování II (návrh)
:Sale
91
Vrstva UI nezpracovává systémové události - NE presses button
Cashier actionPerformed( actionEvent )
UI Layer
:SaleJFrame
It is undesirable for an interface layer object such as a window to get involved in deciding how to handle domain processes. Business logic is embedded in the presentation layer, which is not useful.
1: makeLineItem(itemID, qty)
Domain Layer
:Sale
SaleJFrame should not send this message.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
92
High Cohession Problém: Jak nechat objekty soustředěné, srozumitelné, spravovatelné a jako boční efekt podporovat princip Low Coupling? Řešení: Přiřaď odpovědnost, aby koheze zůstala vysoká. Použij tento princip pro vyhodnocování alternativ.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
93
Př) Kdo zodpovědný za vytváření instance Payment a její spojení se Sale? (1)
Varianta přiřazení zodpovědnosti třídě Register. : Register
: Sale
makePayment() create()
p : Payment
addPayment( p )
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
94
Př) Kdo zodpovědný za vytváření instance Payment a její spojení se Sale? (2)
Varianta přiřazení zodpovědnosti třídě Sale. : Register
: Sale
makePayment() makePayment() create()
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
: Payment
95
High Cohesion – kdy nepoužít, přínos Někdy je oprávněné akceptovat nižší kohezi (např. soustředit zodpovědnost do jedné třídy z důvodu údržby, např. znalost SQL pro mapování na databázi). Přínos: Srozumitelnost, lepší udržovatelnost, zpravidla nízká vazba.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
96
Další principy a shrnutí
Viz Larman str. 413-434.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
97
Další principy a shrnutí
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
98
Další principy a shrnutí
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
99
Příklad použití GRASP při realizaci makeNewSale (1)
Kontrakt systémové operace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
100
Příklad použití GRASP při realizaci makeNewSale (2)
Volba třídy řadiče – je pouze několik systémových operací. :Register
makeNewSale create
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
:Sale
101
Příklad použití GRASP při realizaci makeNewSale (3)
Vytvoření instance třídy Sale.
by Creator and Controller
Register creates a Sale by Creator :Register
makeNewSale create
by Creator, Sale creates an empty collection (such as a List) which will eventually hold SalesLineItem instances
:Sale create
lineItems : List<SalesLineItem>
this execution specification is implied to be within the constructor of the Sale instance © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
102
Případová studie – CD vrstvy domény pro 1.iteraci Store address : Address name : Text
catalog
1 ProductDescription
ProductCatalog
addCompleteSale(...) 1 catalog
... getProductDesc(...)
descriptions description : Text {Map} price : Money 1..* itemID: ItemID ... description
register
1
Sale
Register ... endSale() enterItem(...) makeNewSale() makePayment(...)
1
isComplete : Boolean time : DateTime currentSale 1
lineItems {ordered}
becomeComplete() makeLineItem(...) makePayment(...) getTotal()
completedSales {ordered}
1..*
SalesLineItem quantity : Integer getSubtotal()
*
Payment payment 1
amount : Money ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
103
Případová studie – navázání na vrstvu UI (1)
presses button
Cashier actionPerformed( actionEvent )
UI Layer
:ProcessSale JFrame 1: enterItem(id, qty)
Domain Layer
© J.Zendulka 2006 - 8
system event
:Register
UP - fáze rozpracování II (návrh)
104
Případová studie – navázání na vrstvu UI (2)
Chceme zobrazit celkový součet po každé položce (getTotal). Odkud volat? Register:
+ nízká vazba vrstvy domény na UI - růst rozhraní třídy Register → pokles koheze. třída UI: - zvyšuje vazbu vrstvy UI a domény + je-li Sale stabilní, pak nevadí
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
105
Případová studie – navázání na vrstvu UI (3)
presses button
Cashier actionPerformed( actionEvent )
UI Layer
:ProcessSale JFrame
3: t = getTotal
1: enterItem(id, qty) 2 [no sale] : s = getSale : Sale
Domain Layer © J.Zendulka 2006 - 8
:Register UP - fáze rozpracování II (návrh)
s : Sale 106
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
107
Podstata a historie návrhových vzorů
Osvědčená řešení často se vyskytujících problémů OO návrhu. Popsány strukturovaně → katalog. Historie: Počátky
v polovině 80. let (K.Beck) 1994: Gamma, Helm, Johnson, Vlissides (GoF) : Design Patterns - kniha s 23 návrhovými vzory („bible“ návrhových vzorů). Další: Fowler, Larman (GRASP - General Responsibility Assignment Software Patterns), ... © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
108
Adapter (GoF) Problém: Jak vyřešit nekompatibilní rozhraní nebo poskytnout stabilní rozhraní pro podobné komponenty s různými rozhraními. Řešení: Převést původní rozhraní komponent na jiné rozhraní prostřednictvím pomocného objektu adaptoru.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
109
Adapters use interfaces and polymorphism to add a level of indirection to varying APIs in other components.
«interface» ITaxCalculatorAdapter getTaxes( Sale ) : List of TaxLineItems
TaxMasterAdapter
GoodAsGoldTaxPro Adapter
getTaxes( Sale ) : List of TaxLineItems getTaxes( Sale ) : List of TaxLineItems
«interface» IAccountingAdapter postReceivable( CreditPayment ) postSale( Sale ) ...
«interface» ICreditAuthorizationService Adapter requestApproval(CreditPayment,TerminalID, MerchantID) ...
«interface» IInventoryAdapter SAPAccountingAdapter
postReceivable( CreditPayment ) postSale( Sale ) ...
© J.Zendulka 2006 - 8
GreatNorthernAccountingAdapter
...
postReceivable( CreditPayment ) postSale( Sale ) ...
UP - fáze rozpracování II (návrh)
110
Použití vzoru Adapter :Register
: SAPAccountingAdapter
makePayment ...
SOAP over HTTP postSale( sale ) xxx
«actor» : SAPSystem
the Adapter adapts to interfaces in other components
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
111
Factory (Simple/Concrete) Problém: Kdo by měl být zodpovědný za vytváření objektů, když jde o složitou logiku vytvoření nebo je snaha oddělit zodpovědnost za vytvoření kvůli lepší kohezi atd. Řešení: Vytvořit specielní objekt zodpovědný za vytvoření.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
112
ServicesFactory accountingAdapter : IAccountingAdapter inventoryAdapter : IInventoryAdapter taxCalculatorAdapter : ITaxCalculatorAdapter
note that the factory methods return objects typed to an interface rather than a class, so that the factory can return any implementation of the interface
getAccountingAdapter() : IAccountingAdapter getInventoryAdapter() : IInventoryAdapter getTaxCalculatorAdapter() : ITaxCalculatorAdapter ...
if ( taxCalculatorAdapter == null ) { // a reflective or data-driven approach to finding the right class: read it from an // external property String className = System.getProperty( "taxcalculator.class.name" ); taxCalculatorAdapter = (ITaxCalculatorAdapter) Class.forName( className ).newInstance(); } return taxCalculatorAdapter;
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
113
Singleton (GoF) Problém: Může existovat jen jedna instance, tj. tzv. „singleton“. Objekty potřebují globální a jediný bod přístupu. Řešení: Definovat statickou metodu třídy, která vrátí singleton.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
114
UML notation: this '1' can optionally be used to indicate that only one instance will be created (a singleton)
1 ServicesFactory UML notation: in a class box, an underlined attribute or method indicates a static (class level) member, rather than an instance member
instance : ServicesFactory
singleton static attribute
accountingAdapter : IAccountingAdapter inventoryAdapter : IInventoryAdapter taxCalculatorAdapter : ITaxCalculatorAdapter getInstance() : ServicesFactory
singleton static method
getAccountingAdapter() : IAccountingAdapter getInventoryAdapter() : IInventoryAdapter getTaxCalculatorAdapter() : ITaxCalculatorAdapter ... // static method public static synchronized ServicesFactory getInstance() { if ( instance == null ) instance = new ServicesFactory() return instance }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
115
Abstract Factory (GoF) - motivace Domain JavaPOS
Sales Register
Sale
«interface» jpos.CashDrawer isDrawerOpened() openDrawer() waitForDrawerClose( timeout ) ...
«interface» jpos.CoinDispenser dispenseChange(amount) getDispenserStatus() ...
...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
116
Abstract Factory (GoF)
Problém: Vytvořit rodiny souvisejících tříd, které implementují společné rozhraní. Řešení: Definovat rozhraní „továrna“ (abstract factory) a definovat konkrétní třídu pro vytváření objektů pro každou třídu rodiny tříd. Případně vytvořit abstraktní třídu, která implementuje rozhraní „továrny“ a poskytuje společné služby konkrétním továrnám, které je rozšiřují (varianta Abstract Class Abstract Factory).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
117
this is the Abstract Factory--an interface for creating a family of related objects
«interface» IJavaPOSDevicesFactory getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
IBMJavaPOSDevicesFactory
NCRJavaPOSDevicesFactory
...
...
getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
{ return new com.ibm.pos.jpos.CashDrawer() }
{ return new com.ncr.posdevices.CashDrawer() }
«interface» jpos.CashDrawer com.ibm.pos.jpos.CashDrawer isDrawerOpened() ...
© J.Zendulka 2006 - 8
com.ncr.posdevices.CashDrawer isDrawerOpened() ...
UP - fáze rozpracování II (návrh)
isDrawerOpened() ...
118
// THIS METHOD IS THE USEFUL TRICK public static synchronized IJavaPOSDevicesFactory getInstance() { if ( instance == null ) { String factoryClassName = System.getProperty("jposfactory.classname");
«interface» IJavaPOSDevicesFactory
1
getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
Class c = Class.forName( factoryClassName ); instance = (IJavaPOSDevicesFactory) c.newInstance(); } return instance; }
JavaPOSDevicesFactory instance : IJavaPOSDevicesFactory
1
getInstance() : IJavaPOSDevicesFactory italics indicate abstract methods & abstract class
getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
subclassing an abstract superclass 1
1 NCRJavaPOSDevicesFactory
IBMJavaPOSDevicesFactory ...
...
getNewCashDrawer() : jpos.CashDrawer getNewCoinDispenser() : jpos.CoinDispenser ...
getNewCashDrawer() ... getNewCoinDispenser() ... ...
{ return new com.ibm.pos.jpos.CoinDispenser() }
© J.Zendulka 2006 - 8
{ return new com.ncr.posdevices.CoinDispenser() }
UP - fáze rozpracování II (návrh)
119
Strategy Problém: Jak navrhnout řešení pro lišící se, ale související algoritmy/postupy? Řešení: Navrhnout samostatnou třídu pro každý algoritmus/postup se společným rozhraním.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
120
«interface» ISalePricingStrategy getTotal( Sale ) : Money
PercentDiscount PricingStrategy
AbsoluteDiscount OverThreshold PricingStrategy
percentage : float
??? PricingStrategy ...
getTotal( s:Sale ) : Money
discount : Money threshold : Money
...
getTotal( s:Sale ) : Money
{ return s.getPreDiscountTotal() * percentage }
© J.Zendulka 2006 - 8
{ pdt := s.getPreDiscountTotal() if ( pdt < threshold ) return pdt else return pdt - discount }
UP - fáze rozpracování II (návrh)
121
s : Sale
lineItems[ i ] : SalesLineItem
:PercentDiscount PricingStrategy
t = getTotal loop
{ t = pdt * percentage }
st = getSubtotal t = getTotal( s ) pdt = getPreDiscountTotal
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
note that the Sale s is passed to the Strategy so that it has parameter visibility to it for further collaboration
122
Composite Problém: Jak zpracovat skupinu nebo složenou strukturu objektů stejně (polymorfně), jako by byly atomickým objektem? Řešení: Vytvořit třídu pro kompozit a atomické objekty tak, aby implementovaly totéž rozhraní.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
123
{ ... return pricingStrategy.getTotal( this ) }
All composites maintain a list of contained strategies. Therefore, define a common superclass CompositePricingStrategy that defines this list (named strategies).
Sale date ...
1
«interface» ISalePricingStrategy
pricingStrategy getTotal( Sale ) : Money
getTotal() ...
PercentageDiscount PricingStrategy
AbsoluteDiscount OverThreshold PricingStrategy
1..* strategies
Composite PricingStrategy
percentage : float getTotal( Sale ) : Money
discount : Money threshold : Money
add( ISalePricingStrategy ) getTotal( Sale ) : Money
getTotal( Sale ) : Money
{ return sale.getPreDiscountTotal() * percentage }
CompositeBestForCustomer PricingStrategy
getTotal( Sale ) : Money
CompositeBestForStore PricingStrategy
getTotal( Sale ) : Money
{ lowestTotal = INTEGER.MAX for each ISalePricingStrategy strat in pricingStrategies { total := strat.getTotal( sale ) lowestTotal = min( total, lowestTotal ) } return lowestTotal }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
124
UML: ISalePricingStrategy is an interface, not a class; this is the way in UML 2 to indicate an object of an unknown class, but that implements this interface
:CompositeBestForCustomer PricingStrategy
lineItems[ i ] : SalesLineItem
s : Sale
strategies[ j ] : : ISalePricingStrategy
t = getTotal loop
st = getSubtotal t = getTotal( s )
{ t = min(set of all x) }
loop
x = getTotal( s )
the Sale object treats a Composite Strategy that contains other strategies just like any other ISalePricingStrategy
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
125
Facade
Problém: Požaduje se společné sjednocující rozhraní množiny nesourodých implementací nebo rozhraní, např. podsystému. Může existovat nežádoucí propojení prvků podsystému nebo když se implementace podsystému může změnit. Řešení: Definovat bod kontaktu s podsystémem - objekt „fasáda“, který „zabalí“ podsystém. Tento objekt je jediným sjednocujícím rozhraním a je zodpovědný za spolupráci s komponentami podsystému.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
126
package name may be shown in the tab Domain
+ Sale
+ Register
...
visibility of the package element (to outside the package) can be shown by preceding the element name with a visibility symbol
POSRuleEngine
+ POSRuleEngineFacade
*
instance : RuleEngineFacade
«interface» - IRule
...
... getInstance() : RuleEngineFacade isInvalid( SalesLineItem, Sale ) isInvalid( Payment, Sale ) ... - Rule1 ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
- Rule2 ...
127
Observer (Publish - Subscribe)
Problém: Různé druhy objektů odběratele se zajímají o změny stavu nebo události objektu vydavatele a chtějí reagovat svým způsobem na události generované uživatelem. Navíc vydavatel chce být málo vázán na odběratele. Řešení: Definovat rozhraní odběratele, které implementují konkrétní odběratelé. Vydavatel může dynamicky registrovat odběratele a uvědomuje je, když událost nastane.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
128
Goal: When the total of the sale changes, refresh the display with the new value
Sale total ... setTotal( newTotal ) ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
129
{
{
for each PropertyListener pl in propertyListeners pl.onPropertyEvent( this, name, value );
propertyListeners.add( lis ); }
}
Sale addPropertyListener( PropertyListener lis ) publishPropertyEvent( name, value ) setTotal( Money newTotal ) ... { total = newTotal; publishPropertyEvent( "sale.total", total ); } javax.swing.JFrame ... setTitle() setVisible() ...
propertyListeners
*
«interface» PropertyListener onPropertyEvent( source, name, value )
{ if ( name.equals("sale.total") ) saleTextField.setText( value.toString() ); } SaleFrame1 onPropertyEvent( source, name, value )
{
initialize( Sale sale ) ...
}
© J.Zendulka 2006 - 8
sale.addPropertyListener( this ) ...
UP - fáze rozpracování II (návrh)
130
sf : SaleFrame1
s : Sale
propertyListeners : List
initialize( s : Sale ) addPropertyListener( sf ) add( sf )
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
131
propertylisteners[ i ] : PropertyListener
s :Sale setTotal( total ) publishPropertyEvent ( "sale.total", total ) loop
© J.Zendulka 2006 - 8
onPropertyEvent( s, "sale.total", total )
UP - fáze rozpracování II (návrh)
132
Since this is a polymorphic operation implemented by this class, show a new interaction diagram that starts with this polymorphic version
: SaleFrame1
saleTextField : JTextField
onPropertyEvent( source, name, value ) setText( value.toString() )
UML notation: Note this little expression within the parameter. This is legal and consise.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
133
{ for each AlarmListener al in alarmListeners al.onAlarmEvent( this, time ); {
}
alarmListeners.add( lis ); } AlarmClock addAlarmnListener( AlarmListener lis ) publishAlarmEvent( time ) {
setTime( newTime ) ...
time = newTime; if ( time == alarmTime ) publishAlarmEvent( time ); }
javax.swing.JFrame ... setTitle() setVisible() ...
alarmListeners
*
«interface» AlarmListener onAlarmEvent( source, time )
AlarmWindow
Beeper
ReliabilityWatchDog
onAlarmEvent( source, time ) ...
onAlarmEvent( source, time ) ...
onAlarmEvent( source, time ) ...
{
{
{ display notification dialog box }
© J.Zendulka 2006 - 8
check that all required processes are executing normally
beep }
}
UP - fáze rozpracování II (návrh)
134
presentation
control
PWindow
CActioner
displayContact()
retrieveContact()
entity EConta ct
<>
mediator
foundation
MBroker
FReader
retrieveContact()
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
retrieveContact()
135
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
136
Viditelnost mezi objekty
Schopnost jednoho objektu „vidět“ (mít referenci) na jiný objekt. Tak ví o příjemci class Register { ... private ProductCatalog catalog; ... }
enterItem (itemID, quantity)
: Register
(„vidí ho“)
: ProductCatalog
desc = getProductDesc( itemID )
public void enterItem( itemID, qty ) { ... desc = catalog.getProductDesc(itemID) ... }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
Tak viditelnost použije 137
Způsoby dosažení viditelnosti Viditelnost atributu – B je atributem A. Viditelnost parametru – B je parametrem operace/metody A. Lokální viditelnost – B je lokálním objektem (ne parametrem) metody A. Globální viditelnost – B je nějakým způsobem viditelná globálně.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
138
Viditelnost atributu public void enterItem(itemID, qty) { ... desc = catalog.getProductDesc(itemID) ... }
class Register { ... private ProductCatalog catalog; ... }
enterItem (itemID, quantity)
: Register
: ProductCatalog
desc = getProductDesc( itemID )
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
139
Viditelnost parametru enterItem(id, qty)
2: makeLineItem(desc, qty) :Register
:Sale
1: desc = getProductDesc(id) 2.1: create(desc, qty) :Product Catalog makeLineItem(ProductDescription desc, int qty) { ... sl = new SalesLineItem(desc, qty); ... }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
sl : SalesLineItem
140
Viditelnost parametru na atribut enterItem(id, qty) :Register
2: makeLineItem(desc, qty)
:Sale
2: desc = getProductDesc(id) 2.1: create(desc, qty) :Product Catalog sl : SalesLineItem // initializing method (e.g., a Java constructor) SalesLineItem(ProductDescription desc, int qty) { ... description = desc; // parameter to attribute visibility ... }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
141
Lokální viditelnost
vytvoření lokální instance a přiřazení do lokální proměnné přiřazení vráceného objektu lokální proměnné enterItem(id, qty) { ... // local visibility via assignment of returning object ProductDescription desc = catalog.getProductDes(id); ... }
enterItem (itemID, quantity)
: Register
: ProductCatalog
desc = getProductDesc( itemID )
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
142
Globální viditelnost Globální viditelnost z A k B značí, že B je globální vzhledem k A. Způsoby dosažení:
dosazení
do globální proměnné (C++) použití návrhového vzoru Singleton
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
143
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
144
Mapování modelu návrhu na model implementace PROGRAMOVÁNÍ CD návrhu d. interakce
zdrojový kód, SQL skript pro vytvoření DB, JSP, HTML stránky, …
Programování není mechanický přepis modelu návrhu. Typicky neúplný, během programování a testování je třeba udělat řadu změn, zjistí se a řeší problémy. → návrhový model základem důležitým pro pochopení a řešení problémů zjištěných při programování.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
145
Vytvoření definic tříd z diagramu tříd public class SalesLineItem { private int quantity; private ProductDescription description; public SalesLineItem(ProductDescription desc, int qty) { ... } public Money getSubtotal() { ... } }
ProductDescription SalesLineItem quantity : Integer
description description : Text price : Money 1 itemID : ItemID
getSubtotal() : Money ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
146
Vytvoření metod z diagramů interakce enterItem(id, qty) :Register
2: makeLineItem(desc, qty)
1: desc = getProductDesc(id)
:Sale
2.1: create(desc, qty) :Product Catalog sl: SalesLineItem
1.1: desc = get(id) 2.2: add(sl) : Map
© J.Zendulka 2006 - 8
lineItems : List<SalesLineItem>
UP - fáze rozpracování II (návrh)
147
Př) třída Register public class Register { private ProductCatalog catalog; private Sale currentSale; ProductCatalog
public Register(ProductCatalog pc) {...} public void endSale() {...} public void enterItem(ItemID id, int qty) {...} public void makeNewSale() {...} public void makePayment(Money cashTendered) {...} }
catalog 1
... getProductDesc(...)
Sale Register ...
currentSale
endSale() enterItem(id: ItemID, qty : Integer) makeNewSale() makePayment(cashTendered : Money)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
1
isComplete : Boolean time : DateTime becomeComplete() makeLineItem(...) makePayment(...) getTotal()
148
Př) metoda Register.enterItem { ProductDescription desc = catalog.ProductDescription(id); currentSale.makeLineItem(desc, qty); }
enterItem(id, qty)
2: makeLineItem(desc, qty) :Register
:Sale
1: desc := getProductDescription(id)
:Product Catalog
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
149
Kolekce v kódu
Implementace asociací s násobností „*“ Zpravidla několik typů kolekcí (pole, seznam, …)
public class Sale { ...
Sale isComplete : Boolean time : DateTime
SalesLineItem lineItems
private List lineItems = new ArrayList(); }
Doporučení: implementuje-li třída rozhraní, deklaruj třídu z hlediska rozhraní (tedy ne ArrayList) © J.Zendulka 2006 - 8
becomeComplete() makeLineItem() makePayment() getTtotal()
1..*
quantity : Integer getSubtotal()
A collection class is necessary to maintain attribute visibility to all the SalesLineItems.
UP - fáze rozpracování II (návrh)
150
Př) metoda Sale.makeLineItem { lineItems.add( new SalesLineItem(desc, qty) ); }
enterItem(id, qty)
2: makeLineItem(desc, qty) :Register
:Sale 2.2: add(sl)
lineItems : List<SalesLineItem>
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
2.1: create(desc, qty)
sl: SalesLineItem
151
Pořadí implementace Store
7
address : Address name : Text
1 ProductCatalog
addSale(...) 1
2
ProductDescription
3
... 1..*
description : Text price : Money itemID : ItemID
getProductDesc(...) ... 1 1 Register
Sale
6
isComplete : Boolean time : DateTime
... endSale() enterItem(...) makeNewSale() makePayment(...)
5
1
4
SalesLineItem
becomeComplete() makeLineItem(...) makePayment(...) getTotal() ...
1..*
quantity : Integer getSubtotal()
*
Payment 1
1
amount : Money ...
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
152
Obsah
Logická architektura Závislosti balíčků Architektonické vzory OO návrh - úvod OO návrh - modelovací techniky UML OO návrh – principy návrhu GRASP OO návrh – návrhové vzory Návrh viditelnosti objektů Programování Návrh řízený testem a refaktorizace
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
153
Podstata vývoje řízeného testem (TDD) Praxe prosazovaná iterativními a agilními metodami, aplikovatelná rovněž u UP. Také označovaná jako vývoj principem nejprve testuj (test-first development). Podstata: Nejprve se napíše test a teprve potom se implementuje to, co se testuje.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
154
Výhody TDD
Jednotkové testy se skutečně napíší. Uspokojení programátorů vede ke psaní konzistentnějších testů. Ujasnění si detailního rozhraní a chování. Prokazatelná, opakovatelná automatizovaná verifikace. Důvěra v provádění změn. Podpora TDD – rámce pro jednotkové testování (xUnit – JUnit,NUnit,CppUnit, …).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
155
Př)Ilustrace TDD při vytváření třídy Sale (1)
Před programováním třídy Sale naprogramujeme testovací metodu pro testovací případ ve třídě SaleTest: 1. 2. 3.
Vytvoření instance Sale (tzv. přípravek (fixture)). Přidání několika položek prodeje pomocí metody makeLineItem (tu chceme testovat). Zjištění celkové částky prodeje (použitím getTotal a assertTrue)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
156
Př)Ilustrace TDD při vytváření třídy Sale (2)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
157
Př)Ilustrace TDD při vytváření třídy Sale (3)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
158
Př)Ilustrace TDD při vytváření třídy Sale (4)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
159
Obecný postup TDD při implementaci třídy 1. 2. 3.
Vytvoř testovací třídu. Vytvoř „přípravek“ testované třídy. do Vytvoř testovací metodu:
1. 1. 2.
Aplikuj metodu, kterou testuješ. Ověř očekávané výsledky.
Implementuj testovanou metodu. while implementace vykazuje chyby do
2. 3. 1.
Uprav implementaci
until implementace třídy je úplná © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
160
Integrace do IDE (př.JUnit v Eclipse)
Zelený pruh, až projdou testy
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
161
Podstata refaktorizace (refactoring) Disciplinovaná metoda přepisu nebo restrukturalizace existujícího kódu beze změny vnějšího chování, aplikace malých transformací kombinovaných s opakovaným spouštěním testů. Vede ke snadnějšímu pochopení kódu a usnadnění dalších úprav Soustavná refaktorizace kódu je opět běžná metoda XP a je aplikovatelná na každou iterativní metodu vývoje.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
162
Aktivity a cíle refaktorizace
Odstranění duplicitního kódu Zvýšení srozumitelnosti Zkrácení dlouhých metod Odstranění „natvrdo“ kódovaných literálových konstant … Tzv. „pachy v kódu“ (code smells): duplicitní
kód rozsáhlé metody třída s mnoha atributy nápadně podobné podtřídy silné provázání (coupling) mnoha objektů … © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
163
Příklady typů faktorizace Typ/Vzor Extract Method
Popis Transformuj dlouhou metodu na kratší vyčleněním logické části do privátní pomocné metody.
Extract Constant Nahraď literálovou konstantu konstantní proměnnou. Introduce Explaining Variable
Ulož výsledek výrazu nebo části výrazu do přechodné proměnné se jménem vysvětlujícím smysl
Replace Constructor Call with Factory Method
V Javě se nahradí použití new a konstruktoru voláním pomocné metody, která skryje detaily vytvoření.
Viz http://www.refactoring.com
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
164
Př) Extract Method void printOwing() { printBanner(); //print details System.out.println ("name: " + _name); System.out.println ("amount " + getOutstanding()); }
void printOwing() { printBanner(); printDetails(getOutstanding()); } void printDetails (double outstanding) { System.out.println ("name: " + _name); System.out.println ("amount " + outstanding); } © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
165
Př) Introduce Explaining Variable // good method name, but the logic of the body is not clear boolean isLeapYear( int year ) { return ( ( ( year % 400 ) == 0 ) || ( ( ( year % 4 ) == 0 ) && ( ( year % 100 ) != 0 ) ) ); }
// that’s better! boolean isLeapYear( int year ) { boolean isFourthYear = ( ( year % 4 ) == 0 ); boolean isHundrethYear = ( ( year % 100 ) == 0); boolean is4HundrethYear = ( ( year % 400 ) == 0); return ( is4HundrethYear || ( isFourthYear && ! isHundrethYear ) ); } © J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
166
Př) Replace Constructor with Factory Method Employee (int type) { _type = type; }
static Employee create(int type) { return new Employee(type); }
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
167
Proč refaktorizujeme (M. Fowler) Refaktorizujeme proto, abychom zlepšili návrh software. Refaktorizace vede k lepší srozumitelnosti software. Refaktorizace pomáhá hledat chyby - lepší pochopení kódu při refaktorizaci. (K.Beck: „Nejsem skvělý programátor, jsem pouze dobrý programátor se skvělými návyky.“)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
168
Kdy refaktorizujeme (M. Fowler) (1) Refaktorizujeme místo třetího opakování („Poprvé to prostě uděláš, podruhé se rozmýšlíš kvůli duplicitě, ale uděláš to, ale potřetí bys měl refaktorizovatat.“) Refaktorizujte před přidáním funkcionality (nejčastější případ refaktorizace). Refaktorizujte při opravách chyb (lepší pochopení kódu) a při revizi kódu.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
169
Některé užitečné zásady (M. Fowler) (1) Když zjistíte, že do programu musíte přidat novou funkci a přitom jeho struktura k tomu není vhodná, nejprve v programu refaktorizujte tak, aby přidání funkce bylo snadné a teprve pak funkci přidejte. Než začnete refaktorizovat, zkontrolujte, jestli máte kvalitní sadu testů, které se samy vyhodnocují.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
170
Některé užitečné zásady (M. Fowler) (2) Refaktorizace mění programy po malých krocích. Pokud se spletete, je jednoduché chybu najít. Kód, kterému rozumí počítač, dokáže napsat každý. Dobří programátoři píší kód, kterému rozumí lidé.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
171
Problémy s refaktorizací Jednou z problematických oblastí jsou databáze (většina podnikových aplikací je těsně spojena se strukturou databáze, navíc problémy s nutností migrace dat při změně struktury). Řešení u neobjektových databází: vrstva oddělující databázový a objektový model (při změně nutno aktualizovat jen oddělující vrstvu).
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
172
Podpora refaktorizace v IDE (Eclipse) (1)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
173
Podpora refaktorizace v IDE (Eclipse) (2)
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
174
Dopředné, zpětné a round-trip inženýrství Týká se podpory nástrojů CASE Dopředné (forward) - generování kódu z modelu (zpravidla diagramu). Zpětné (reverse) – generování modelu (zpravidla diagramu) z kódu. Round-trip – obousměrné generování a synchronizace modelu a kódu.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
175
Literatura (1)
Larman, C.: Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development. Prentice Hall, 2005, pp. 197 - 472. Starší vydání je na http://books.google.com/books?id=r8i4En_aa4C&printsec=frontcover&dq=larman&hl= cs Maciaszek, L.A., Liong, B.L.: Practical Software Engineering. A Case Study Approach Addison Wesley, Harlow England, 2005, 864p.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
176
Literatura (2) BECK, K.: Programování řízené testy. Grada Publishing, 2004. Fowler, M: REFAKTORING Zlepšení existujícího kódu. Grada, 2003.
© J.Zendulka 2006 - 8
UP - fáze rozpracování II (návrh)
177