You are on page 1of 21

Elementary Pattern, GRASP e Design Pattern GoF

Object Oriented
Rosario Turco

Introduzione Nel lavoro precedente [DR18] sono stati presentati gli Elementary Pattern (EP), gli Anti Elementary Pattern (AEP), i GRASP (General Responsibility Assignment Software Patterns).. Gli EP esaminati sono stati: Elementary Pattern Complessit e Riusabilit di una classe Anti Elementary Pattern di Coesione (istanza, dominio misto, ruolo misto) Elementary Pattern Conformita di tipo Elementary Pattern dellInvariante Elementary Pattern della precondizione Elementary Pattern della postcondizione Elementary Pattern - Principio del comportamento chiuso alle modifiche Elementary Pattern della classe Astratta o dellInterfaccia Elementary Pattern Classe Mista Elementary Pattern Descrittore di Classe Elementary Pattern Separation of concerns Elementary Pattern Lazy initialization

Vedremo che esistono molti altri EP. I GRASP esaminati sono stati: Information Expert Creator Low Coupling High Cohesion Controller Polimorfismo Pure Fabrication Indirection Procted Variations

Testo rigoroso e storico sui Design Pattern quello in [DR6]. Una trattazione in chiave di classificazione dei Design Pattern GoF, il loro scopo e una loro modellazione stata prodotta dallautore in *DR5+. In questo lavoro vogliamo, invece, vedere i Design Pattern GoF (DP) attraverso gli EP e i GRASP. Arrivando a sottolineare ulteriori Elementary Pattern e Pattern Architetturali. 1

La trattazione non da ritenersi esaustiva, ma serve a sottolineare il metodo per comprendere cosa possa servire nella progettazione o come validare la propria progettazione. Gli EP e I GRASP sono principalmente concetti, principi e regole di buon senso Object Oriented, adottate nel tempo. I Design Pattern e i Pattern Architetturali cerano di risolvere problemi ricorrenti, dando flessibilit e solidit al progetto, individuando i punti di variazioni futuri possibili (Variability Analysis) e i punti progettuali fragili (Commonality Analysis). Esiste, quindi, una granularit diversa che ci porta a trovarli frequentemente in determinati ambiti. Ad esempio solo se facciamo un sistema di Persistenza dati, troveremo altri Elementary Pattern come: Etc. Se lavoriamo con framework o prodotti di persistenza questi EP non saranno aspetti progettuali che ci interesseranno, ma saremo concentrati rispetto al nostro dominio. Il lavoro mostrer in prima battuta come alcuni DP discendono in modo semplice dagli EP e/o dai GRASP; poi ogni DP, per ragioni di flessibilit, attraverso considerazioni GRASP, comporta quasi sempre la presenza anche di altri DP che si rendono necessari nella progettazione, insieme a nuovi EP non esaminati nel lavoro precedente. Infine si descriveranno anche dei Pattern Architetturali. DP Adapter Problema: Come risolvere il problema di conciliare interfacce differenti da usare o fornire una stabile interfaccia (nel senso che non si modifica di continuo) a componenti simili ma che hanno interfacce diverse? Soluzione: Convertire linterfaccia di un oggetto in quella di un altro attraverso un oggetto mediatore o adattatore. Esempio Supponiamo che un nostro dispositivo deve usare calcolatori di tassa esterni, che possono essere sia cambiati o aggiunti ma hanno comportamento diverso. Object Identifier (OID chiave tra oggetto e riga di una tabella), Materialization (come rendere una riga di tabella un oggetto) Dematerialization (come rendere un oggetto una riga di tabella, detto anche passivazione) Cache

In pratica qui usiamo almeno in prima battuta lidea del GRASP Polimorfismo, del GRASP Procted Variation e lEP della classe astratta o dellinterfaccia (basata sul Partizionamento completo). Il progettino in prima battuta si presenta come nella figura successiva.

Le classi Adapter sono classi locali che poi chiameranno eventuali API dei calcolatori esterni. Quindi fanno da GRASP Indirection. Il template <T> ci permette di avere il partizionamento completo e usare la interfaccia. Linterfaccia ci permette di incapsulare un punto di variazione potenziale e quindi applicato anche il GRASP Procted Variations. Infine il minor ingombro diretto e indiretto possibile ottenendo Low Coupling e High Cohesion. Adesso usiamo ancora i GRASP, in senso generale. I GRASP ci suggeriscono chi ha la responsabilit per . Qui nasce subito il problema: chi crea lAdapter? Sicuramente vero lEP Lazy inizialization, nel senso che in fase di sviluppo difficile che si inizializzino e si creino attraverso i costruttori tutte le classi e poi si usano dopo. Semmai le classi si creano quando servono, perch un dispendio di risorse. Quindi evidente che lAdapter associato ad una Factory (quella Concrete come vedremo) e anche a qualche altro DP. La Factory in termini GRASP ci risolve la responsabililt del Creator per lAdapter, del Pure Fabrication ( un Helper) e lEP di Separation of concerns. La Factory deve decidere anche quale calcolatore mettere su, ad esempio in modalit DATA-DRIVEN o da configurazione. E possibile cio progettare una ServiceFactory come in figura, che ritorna oggetti di tipo dellinterfaccia.

Questo tipo una Concrete Factory, perch provvede direttamente a creare loggetto di interesse, in questo caso lAdapter. La Factory permette anche strategie non funzionali e di indirezione come il Caching, riduce la complessit della parte di logic che dovrebbe essere concentrata solo sul dominio aziendale. Molti framework (es: Spring) usano una factory per caricare oggetti o bean a partire da un file di configurazione XML. 3

DP Factory Problema: A chi dare la responsabilit per risolvere il problema di creazione di un oggetto ma semplificando la complessit della parte logica, in modo da avere basso accoppiamento con altri elementi di dominio diverso e la separazione dei concetti? Soluzione: Dare la responsabilit ad un Pure Fabrication Object denominato Factory che gestisce la creazione delloggetto. Fin qua siamo soddisfatti, ma la GRASP ci pone un altro paio di domande: chi crea la Factory? quante factory devono esistere? Sicuramente nel caso di un Adapter ci servir una sola istanza di Factory per volta. Quindi La factory deve essere anche un Singleton. Possiamo usare un attributo di istanza statico a s stesso e un metodo statico. In UML sia gli attributi statici che i metodi statici sono sottolineati, ma non tutti i tool lo visualizzano in tal modo, alcuni come StarUML permette di marcare lattributo e il metodo con TARGETSCOPE = INSTANCE e Owner Scope = INSTANCE.

Il synchronized va valutato se inserirlo in dipendenza se ci sono problemi di multi-thread oppure no. Nella pratica un oggetto Register potrebbe avere nel codice la seguente parte: public class Register { . Etc . taxCalculatorAdapter = ServiceFactory.getInstance().getTaxCalculatorAdapter(); }

Sui diagrammi UML di un sequence il passaggio intermedio a getInstance() potrebbe non essere visibile, cio viene ritenuto implicito, ma nellimplementazione necessario.

Se si vuole esplicitare che ci deve essere il Singleton allora meglio esplicitare il tutto almeno nel nome delal ServiceFactory, trasformandolo in ServiceFactorySingleton e mettendo un commento. In ogni caso c una condizione sul create(). Ci si chiede: perch in ServiceFactory non facciamo tutti attributi e metodi statici? Le risposte sono: Intanto per non violare la concetto di incapsulamento e di data-hiding, caro allOO che risolve i problemi di co-nascenza dei linguaggi procedurali I metodi statici non sono soggetti apolimorfismo e non permettono loverriding Nelle comunicazioni di rete remote (come RMI) sono possibili solo metodi di istanza e non metodi statici DP Singleton Problema: Come ottenere che ci sia il controllo sul fatto che esista una sola istanza di una classe, a causa del fatto che la continua creazione di istanze un fatto costoso in termine di tempo e risorse? Soluzione: Dare la responsabilit ad un Singleton.

Passiamo ad un altro problema che ci pu capitare: spesso si hanno problematiche di logica complessa, ad esempio di stabilire in una vendita (Sale), in base al totale da pagare da un tipo di cliente (normale, gold, etc), lo sconto e il prezzo che gli si pu applicare. Tipicamente sono problemi dove si applicano regole diverse o algoritmi diversi a seconda di determinate situazioni. Il DP Strategy utile proprio a questo. DP Strategy Problema: Come progettare/disegnare/modellare per contenere le variazioni di algoritmi, regole, policy? Soluzione: Dare la responsabilit ad uno Strategy. GRASP e EP sui cui si basa anche lo Strategy sono: GRASP Polimorfismo GRASP Procted Variation EP della classe astratta o dellinterfaccia (basata sul Partizionamento completo). allo Strategy sempre associato ad un Context Object (nellesempio la vendita Sale). Un primo progettino , quindi, quello in figura. 5

La classe PercentDiscount chiede a Sale (Expert) quanto era il conto totale senza sconto. Mentre AbsoluteDiscount chiede a PercentDiscount (Expert) il conto scontato (se scontabile). Il metodo getPreDiscountTotal() ovviamente di Sale. Entrambi le classi usano Sale (Context Object). In sostanza c una collaborazione.

I GRASP pongono adesso il seguente quesito: chi la responsabilit di creare lo Strategy? Ovvero sono da applicare di nuovo il GRASP Creator e EP Lazy Initialization. La risposta una Factory. Altra domanda GRASP: ma quante istanze di strategy sono permesse? Nel caso una, per cui il Singleton diventerebbe dobbligo. Per cui la Factory dovrebbe avere anche un attributo di istanza e un metodo statico. In figura la soluzione col Singleton.

In ultima analisi se serve uno DP Strategy, allora lo troveremo accoppiato quasi certamente ad una Factory, ad un Context Object, ed eventualmente ad un Singleton. Ma potrebbero essere utili anche altri DP a seconda della complessit del problema come vedremo. Facciamo qualche altra osservazione, prima. La percentuale di sconto potrebbe dipende dal giorno (es.: luned 10%, marted 20% etc.) o dal tipo di cliente. In tal caso queste percentuali saranno configurate su un properties o su un database relazionale. Chi dovrebbe leggere questi dati per passarli allo Strategy? Una scelta ragionevole la PricingStrategyFactory stessa. Essa conosce i dati che legge, conosce la strategia di pricing e quindi costituisce lExpert. Supponiamo adesso che per le policy di pricing ce ne sono molte e sono in conflitto. Ad esempio le policy in gioco sono oggi luned: 20% di sconto ai clienti gold 15% di sconto alle vendite che superano i 400 euro Il luned ci sono almeno 50 euro fuori acquisto sul totale di 500 euro Acquistando il prodotto X si ottiene uno sconto del 15% su ogni altro prodotto Almeno tre delle situazioni di sopra comportano sconto.

Alcuni store potrebbero applicare lo sconto migliore a partire da un totale pi basso (a favore del cliente), oppure la vendita ha sconti diversi per prodotto etc. In ogni caso questo evidenzia un chiaro conflitto di strategia. Intanto che il cliente sia gold qualcosa che deve leggere la PricingStrategyFactory al tempo di creazione dello Strategy. Se lo sconto va fatto per prodotto acquistato significa che abbiamo dietro un EP Descrittore di classe, un ProductDescription, che deve leggere la PricingStrategyFactory per determinare per ognuno lo sconto. Rimane ora un problema. C un modo affinch loggetto Sale non conosca a priori se esiste un legame con uno o pi strategie di prezzo? Esiste anche un modo per risolvere i conflitti di strategie? Occorre introdurre il DP Composite.

DP Composite Problema: Come trattare un gruppo di oggetti o composizione di oggetti come oggetti non atomici? Soluzione: Usare il Composite, cio definire classi per oggetti composti e atomici cos che essi implementino la stessa interfaccia. Supponiamo una nuova classe che definisce la miglior strategia per il cliente gold: CompositeBestForCustomerPricingStrategy che implementa iSalePricingStrategy e contiene altri oggetti sempre di tipo ISalePricingStrategy. Riprendiamo una figura precedente, quella senza Factory, e cerchiamo di arricchirla.

In figura il Composite superclasse ha una lista di strategie: CompositePricingStrategy punta alla interfaccia a tale scopo per disporre di una lista. E una caratteristica del Composite. Come si vede dalla superclasse si hanno due sottoclassi, una per la migliore strategia del cliente e laltra per lo Store. La figura fa vedere che a Sale possibile collegare oggetti semplici o compositi per far uso o di una strategia puntuale come PercentDiscount o una particolare CompositeBestForCustomerStrategy che serve a determinare il pi basso totale a cui fare lo sconto. IL Sale in questo caso non sa n le regole atomiche n quelle complesse. Nella figura non abbiamo riportato la Factory, che andrebbe per riportata. Il problema difatti capire come creare con la Factory per i diversi Strategy. Finora abbiamo supposto che ci sono almeno tre sconti (dovremmo saperlo dagli Use case): Definiti per lo Store e che vengono aggiunti quando Sale creata (le percentuali di partenza definite in PercentDiscount). Definiti per il tipo di cliente, aggiunti quando il cliente arriva al POS che legge dalla sua carta che gold Definiti in base al prodotto Nel primo use case la class name della strategy da far partire letto da system properties, cos pure le percentuali vengono lette da DB, dalla Factory. 9

Questo primo use case ha il sequence della figura successiva.

Il secondo use case rappresentato nella figura successiva. Ovviamente poich il cliente pu essere gold o normal, allora bisogna individuare da DB con lIDCustomer prelevato dalla scheda se gold o meno.

Perch un IDClient si poi trasformato in un oggetto Customer. E una pratica comune, un Elementary Pattern IDs to Objects. Spesso serve prelevarsi dallID le informazioni dellintero oggetto. E un esempio. Se non serve si passa solo lID. Anche trasformare un ID in ProductSpecification simile come pattern. Un altro fatto che mette in mostra la figura che addCustomerPricingStrategy(s:Sale) passa loggetto Sale alla factory e la factory torna indietro da Sale a chiedere Customer e il PricingStrategy. Perch non passare direttamente alla Factory Customer e il PricingStrategy ? Questo un comune metodo OO consigliato: per aumentare la flessibilit progettuale evitare di passare sottooggetti di oggetti padri o di aggregati, meglio passare loggetto padre o laggregato! Inolte si ritarda il fatto che la factory debba sapere prima del tempo quello che gli serve. Questo viene chiamato Elementary Pattern Aggregate Object as Parameter.

10

DP FACADE Problema: Come disporre di un unico punto di ingresso al sottosistema, con ununica interfaccia, che permette di nascondere quello che c dietro e che potrebbe variare? Soluzione: Usare un Facade object, che offre ununica interfaccia e collabora con le varie parti del sottosistema (ma senza logica di business). Il Facade un front-end di accesso ai servizi del sotto-sistema, ne wrappa dietro le classi e le interfacce offerte, non rendendoli visibili allesterno (sono privati al sistema). Quindi rispetta il GRASP Procted Variations, rispetto alle variazioni. Nasconde sia la complessit del sottosistema, che eventuali interfacce non implementate ancora. In sostanza c anche il GRASP Indirection o al contrario lElementary Pattern Delegate; infatti lesperto il sottosistema a cui il Facade delega la competenza. In tal modo si supporta il GRASP Low Coupling. Supponiamo ad esempio un sottosistema che un motore di regole, di cui non stata fatta limplementazione, e sicuramente il client non deve conoscere la singola classe da chiamare. E da considerarsi spesso un Front Controller, quindi esiste dietro anche lElementary Pattern Controller, perch fa da coordinatore della varie parti del sottosistema da coinvolgere. Si insiste molto sui termini Front-end, sottosistema. Quindi il Facade un tipico DP architetturale o come nella classificazione GoF un DP strutturale. In J2EE il Facade un compito svolto da un EJB Session Bean stateless; in rari casi da un EJB Session Bean Stateful. Il Facade pu portarsi appresso anche un DP Adapter, che a sua volta pu richiederne altri o un Singleton. In figura mostriamo lorganizzazione a package e delle classi su StarUML.

11

DP OBSERVER (Publish-Subscribe o anche Delegation Event Model) Problema: Differenti oggetti devono svolgere il proprio lavoro ma nello stesso tempo sono interessati al verificarsi di un evento su cui devono svolgere particolari task. Come fare? Soluzione: Usare lObserver. In esso differenti tipi di oggetti denominati Listener interface o Subscriber (Sottoscrittore) sono interessati ad un evento, che costituito dalla variazione di stato di un attributo. Per tale motivo ogni Subscriber si sottoscrivono (registrano) in modalit asincrona ad un Publisher per un evento. Il Publisher avverte i Subscriber registrati allevento solo al verificarsi dellevento stesso. Si chiama Observer perch il Subscriber tiene docchio levento, come un osservatore. Esempio Supponiamo che vogliamo realizzare una GUI che quando listanza della classe Sale cambia il valore del totale della vendita fa refresh del valore a video. Per le User Interface, Web e non, si utilizza il pattern Model-View-Controller. Il Model (Sale in questo caso, ovvero il modello del dominio) non deve avere alcuna conoscenza della View. Questo concetto incoraggia i GRASP Low Coupling e Procted Variation. Per poter ottenere questo serve realizzare un DP Observer. Il Model Sale il Publisher (colui che pubblica la variazione di stato), mentre il Subscriber o Listener Interface la View che deve fare refresh. Il Subscriber per si deve registrare al Publisher per levento. 12

In figura lObserver che serve realizzare. Supponiamo che usiamo classi di Swing per la UI. Anche qua si pu lavorare tra due package, uno Domain contenente Sale e laltro UserInterface contenente il Listener Interface. Ovviamente il package Domain <<usa>> il package UserInterface. Nel seguito abbiamo preferito di mostrare le classi insieme. Sale ha almeno: Il metodo che setta il nuovo valore del totale: setTotal(Money) Il metodo che consente ai Subscriber di sottoscriversi a Sale: addListener(Listener lis) Il metodo per pubblicare ai Subscriber la variazione del valore: publishEvent(name, value) Il Listener Interface deve avere almeno: Il metodo che riconoscendo levento a cui si sottoscritti effettua il refresh: onEvent(source, name, value). Tale metodo chiamato dal Publisher e costituisce la callback. Un metodo add per tener conto dei listener sottoscritti

source s, cio Sale. Name sale.total, value total. Nel seguito il sequence d ulteriori chiarimenti. addListener() far qualcosa come: propertyListeners.add(lis); Il publishEvent() far qualcosa come: { for each IListener pl in propertyListeners pl.onEvent(this,name, value); 13

Lesempio non deve far pensare che lObserver serva solo per le User Interface. Spesso utile anche per la parte server. Ad esempio per ricaricare una cache.

Esempio di Failover di una cache ad un local service Dobbiamo trovare una descrizione di un prodotto. Essa presente attraverso un servizio su un database. Per efficienza ci serve una cache che li legge da locale se ce li ha se no va verso il servizio remoto. Pensiamo di usare un Adapter (che verr creato da un ServiceFactory). Anche se realmente non un Adapter, a due livelli. In realt un Proxy (Remote Proxy, Virtual Proxy o Failure Proxy). Qua non abbiamo riportato il ServiceFactory che riportiamo nel sequence.

14

Il Proxy inizialmente fornisce un riferimento temporaneo; esempi sono: Gestione dei failover di connessioni, cache etc Nel Web per visualizzare subito il contenuto testuale delle pagine HTML, fornendo un segnaposto iniziale per le immagini, che vengono caricate successivamente nel Java RMI fornendo un oggetto locale per poi comunicare successivamente con loggetto remoto Per le eccezioni alzate vale un Elementary Pattern Convert Exceptions [Brown01]: se si a livello di sottosistema non alzare eccezioni di pi basso livello non coerenti col sottosistema ma convertirle. Per il logging vale un Elementary Pattern Centralized Error Logging [Renzel97]: definire un oggetto acceduto in modo centralizzato e Singleton e riportare ad esso tutte le eccezioni. Vale per le UI un analogo un Elementary Pattern Error Dialog [Renzel97]: definire un oggetto acceduto in modo centralizzato e Singleton con cui notificare agli utenti gli errori. DP ABSTRACT FACTORY Problema: Come creare una famiglia di classi legate che implementano una interfacce comuni? Soluzione: Definire una factory interface, con tutti i metodi.

15

16

DP Template Method E di enorme importanza nei framework (vedi *DR19+ per esempi e principi sui framework) . Consiste nel fatto che in una classe due metodi di cui uno implementato e che richiama un secondo non implementato, mentre la sottoclasse implementa il secondo metodo e ne fa loverriding polimorfico. Nella superclasse il primo metodo, che NON VARIA e che richiama il secondo metodo non implementato, si chiama per questo template; mentre il secondo metodo detto hook (uncino daggancio). Il principio su cu si basa il Template Method un Elementary Pattern Principio di Hollywood: Non chiamateci, vi chiamiamo noi (tramite lhook)! Ad esempio si possono fare framework per giochi che hanno una stessa base dinfrastruttura (*DR19+) oppure dei Mapper diversi (da file, DB, da JMS, etc) In figura quanto detto sopra.

Il DP Template Method esalta lEP Protected Variations. DP State Pattern Problema: Il comportamento di un oggetto dipende dal suo stato e i suoi metodi contengono logica che legata a questi stati Soluzione: Usare lo State Pattern. Esempio Gli oggetti di un sistema persistente possono essere inseriti, cancellati o modificati. Supponiamo per che lavorare su un oggetto persistente non provoca subito la modifica delloggetto sul database ma una esplicita commit deve essere effettuata. Un diagramma di stato per un PersistentObject potrebbe essere quello in figura.

17

Come gestirlo con un modello di classi? Vediamo la figura successiva.

Sulle classi che esprimono lo stato troveremo i metodi che fanno uscire dallo stato in questione. Lesempio qui visto solo didattico, per trasportarlo in situazioni simili ma non di persistenza; per la persistenza meglio usare un framework come Hibernate, MyBatis etc.

DP Command Pattern Problema: Come gestire richieste, comandi o task che necessitano di applicazioni di funzionalit come sorting, queuing, logging, undoing, etc. Soluzione: Usare il Command Pattern, facendo ogni task una classe che implementa una interfaccia

18

Esempio Supponiamo di avere un oggetto Transaction che deve far eseguire una lista di comandi. Pu delegare ad un esperto (il Command)

19

Abbiamo, quindi, finora esaminato i seguenti Design Pattern sotto una lente EP e GRASP: Adapter Factory Strategy Composite Facade Observer Proxy Abstract Factory Template Method State Pattern Command Pattern

Abbiamo poi incontrato degli EP ulteriori: Context Object (sono utili non solo nello Strategy, sono dei particolari Data Transfer Object) Lazy Initialization IDs to Objects Aggregate Object as Parameter Convert Exceptions Centralized Error Logging Error Dialog Principio di Hollywood MVC (Model View Controller) LMVC un pattern architetturale. Per una UI desktop con Swing lObserver proposto pu andar bene. Per UI web si usano framework che gestiscono lMVC come Spring, Struts2 (lato server) o JavascriptMVC (lato client). Lo standars POSA (Pattern-Oriented Software Architecture) indica che esistono almeno tre tipologie: Pattern architetturali (PA) Design Pattern, alcuni visti primi Idiomi, che indirizzano problemi di linguaggio o di basso livello. Anche il Singleton di questo tipo, oltre che essere un DP. Un altro Pattern Architetturale importante il Layer. PA Layers Problema: 1. Il sw cambia spesso creando instabilit, molte parti sono fortemente accoppiate 2. Lapplication logic troppo connessa e intrecciata alla UI 3. Servizi tecnici e di business sono intrecciati 4. Forte connessione tra area diverse Soluzione: organizzare il sistema a strati (layer), ognuno dei quali risolve una serie di sotto problemi e collabora con gli altri Nel sw di un sistema tipicamente si ritrovano ad esempio i seguenti package che seguono il PA Layers: 20

Presentation Application (Workflow, Process, Mediation, Controller) Domain (dominio di business) Business Infrastructure (opzionale: servizi di business di basso livello) Technical Services (Infrastruttura tecnica, servizi tecnici) Foundation (opzionale: Infrastruttura di basso livello, servizi tecnici di basso livello)

Per i rimanenti DP qui non trattati si consiglia di esaminare [DR5][DR6].

Riferimenti

[DR1] Rosario Turco Concetti di base Object Oriented [DR2] Rosario Turco Principi di Disegno [DR3] Rosario Turco Usabilit e ripetibilit dei processi produttivi software [DR4] Rosario Turco Modellare con lUML ed i colori [DR5] Rosario Turco Design Pattern Pattern e-book: una guida nella jungla dellOO [DR6] Gamma, Helm, Johnson,Vlissides Design Patterns Elementi per il riuso di software a oggetti Prima edizione italiana [DR7] Rosario Turco Risoluzione di problemi con UML [DR8] Rosario Turco Tradurre le relazioni UML in C++ [DR9] Rosario Turco - Refactoring: la teoria in pratica [DR10] Rosario Turco Disegno per il riuso e con il riuso [DR11] Rosario Turco Framework e UML [DR12] Rosario Turco Il Business AS IS Modeling con UML [DR13] Rosario Turco Extreme Programming [DR14] Rosario Turco Rational Unified Process [DR15] Rosario Turco BPM, SOA e Business Rules Engine, lultima frontiera [DR16] Rosario Turco Progettazione a componenti [DR17] Rosario Turco - Metodologia Agile [DR18] Rosario Turco Elementary Pattern, Anti Elementary Pattern e GRASP [DR19] Rosario Turco Principi sui framework software

21

You might also like