Top Banner
Programmazione Object-Oriented per utenti di CMSSW Mini-corso, Padova, 22/04/2010 Massimo Nespolo 1
34

Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Feb 14, 2019

Download

Documents

trinhdat
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Programmazione Object-Oriented

per utenti di CMSSW

Mini-corso, Padova, 22/04/2010

Massimo Nespolo

1

Page 2: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Riassunto:

• Refactoring:

– Come far evolvere il codice.

– In che direzione andare.

– A che livello agire.

• Design pattern (GoF):

– Che cosa sono.

– Perché parlarne.

– Qualche esempio.

Refactoring e design pattern

2

Page 3: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

I principi di design

3

Linee guida principali (SOLID) che permettono di

evitare un cattivo design (rigido, fragile, immobile)

Bisogna però bilanciare sempre vantaggi e svantaggi:

aggiungono complessità, e vanno usati dove serve flessibiltà

1. S - SRP: Single responsibility principle.

2. O - OCP: Open/closed principle.

3. L - LSP: Liskov substitution principle.

4. I - ISP: Interface segregation principle.

5. D - DIP: Dependency inversion principle.

Page 4: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Refactoring

4

Il codice “brutto” non va

spiegato mediante commenti:

va riscritto. I commenti sono

per le intenzioni!

Modifica della struttura interna

di un programma eseguita

senza cambiare il

comportamento funzionale

Se non riusciamo ad ottenere quanto descritto in precedenza

al primo colpo, conviene fermarsi e rimettere mano al codice

Le nostre idee devono sempre essere

espresse mediante il linguaggio

Page 5: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

A volte il codice “puzza”

5

Si chiamano “puzze” (smells) i segnali

che un codice è di bassa qualità

1. Duplicate code:

Effetto del copia-incolla, ma bisogna fare una analisi “globale”.

2. Long method e long parameter list:

Codice troppo specializzato, difficile da leggere e riusare.

3. Primitive obsession:

Non lavoriamo al giusto livello di astrazione.

4. Large class, lazy class, data class, divergent change:

Classi troppo ricche, troppo povere, o troppo “mescolate”.

5. Switch statement, conditional complexity e shotgun surgery:

Diventano rapidamente ingestibili (indice di Mc Cabe).

Page 6: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Schema di massima

6

Refactoring può coinvolgere diversi livelli (dal piccolo al grande):

1. Impacchettare adeguatamente il codice in funzioni.

2. Rendere più semplici le chiamate ai metodi.

3. Spostare variabili e metodi da una classe all’altra.

4. Organizzare i dati (cont. diretto/indiretto, type code, …).

5. Semplificare le espressioni condizionali (decomposizione).

6. Gestire le generalizzazioni (gerarchie di derivazione, interfacce).

7. Cambiare l’organizzazione del programma.

Se succede (per imperizia,

cambiamento delle condizioni

esterne, …) si rifattorizza

Evoluzione/ripulitura del codice

fatta in modo disciplinato per

minimizzare il rischio di bug

Page 7: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Nomi comunicativi

7

I nomi di variabili e funzioni

vanno legati al problema

Effettuiamo un rename

(semplice ma efficace)

Usiamo sostantivi per le variabili (cose),

e verbi per le funzioni (azioni)

Spesso da qui partono

refactoring più complessi

Emergono relazioni tra variabili

e funzioni prima nascoste

Il nome di una funzione è

formato da 2 verbi. È giusto?

Page 8: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

A livello di funzioni

8

Con pochi parametri (7±2),

allo stesso livello di astrazione

Non è banale scrivere funzioni “belle”,

ossia facili da leggere e da riutilizzare

Funzioni corte

(1, massimo 2 schermate)

Questa è la strategia fondamentale per

rimuovere il codice duplicato:

mettiamolo in una funzione separata.

Catene di operazioni booleane

tra variabili dentro un if

Estraggo tutto dentro una

funzione con nome adatto

Page 9: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Extract class/subclass

9

Spesso ci si accorge che le funzioni di un gruppo si

passano sempre gli stessi parametri: eliminiamoli!

Nuova classe con quelle

funzioni e quelle variabili

Se siamo già in una classe,

estraiamo una sotto-classe

Partiamo quindi con classi

semplici, ed aggiungiamo

funzionalità nuove

Se la classe diventa troppo

complessa, rifattorizziamo

estraendone una parte

Page 10: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Usiamo bene le gerarchie

10

Una sottoclasse “è-una” classe base,

ma in C++ eredita anche dati e funzioni

Se c’è del codice duplicato

nelle classi derivate

Sistemiamo i nomi, e spostiamo

tutto nella classe base

Se qualcosa nella classe base è

usato solo da poche derivate

Spostiamo quello che non è

comune verso il basso

EreditarietàContenimento

Qualche volta, si può fare lo scambio

Page 11: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Metodi al livello giusto

11

Pull-up

method

Pull-down

method

Page 12: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Un caso dubbio…

12

Uno studente “è-una” persona Ereditarietà

E per chi studia e lavora? Eredito da

ambedue (ereditarietà multipla, ed

in C++ deve essere virtuale).

Il lavoratore “è-una” persona Ereditarietà

Ma queste relazioni non

possono più cambiare

(l’ereditarietà è statica)

virtual virtual

Page 13: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Soluzione

13

Stavamo confondendo essere ed avere!

Una persona ha un’attività, che

può cambiare nel tempo

Contenimento mediante

“classi ruolo” (astratte)

Il contenimento è una relazione

dinamica, che può cambiare

Persona non dipende da

Lavoro o Studio (DIP)

Contenimento

Ereditarietà

Page 14: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Extract interface

14

Ma attività è una classe astratta, che deve/può

avere varie realizzazioni concrete

Se abbiamo già le classi concrete, estraiamo

un’interfaccia unica come generalizzazione

Facilità di lettura

(compiti separati)

DIP

(dettagli isolati)

Hot-spot

(possiamo estendere)

Page 15: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Switch e condizioni sparpagliate

15

Gli switch (if-else) sono la

prima fonte di complessità

Nascono innocenti,

ma crescono male

Ancora peggio se la catena

si ripresenta in più punti

Devo fare modifiche in

parallelo (shotgun surgery)

Nuovi comportamenti

aggiungono nuove clausole

Da qui originano difficoltà

di lettura, bachi, rigidità

Page 16: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Polimorfismo (ancora)

16

Lavoratore lavoratore;

Studente studente;

if ( adessoSiamoInEstate ) {

lavoratore.lavora();

} else {

studente.studia();

}

Persona* p = new Persona;

p->setStatus(Persona::Studente);

p->FaiQuelCheDevi() ;

In un programma ad oggetti,

non dovrebbero esserci if-else

Utilizziamo interfacce e

polimorfismo (late binding)

Il polimorfismo è il sostituto ad oggetti dello switch

Page 17: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Dagli switch ai pattern

17

La logica condizionale (switch)

può avere diversi effetti sugli oggetti

Algoritmi diversi

per un problemaStrategy

Cambio di comportamento

a seconda dello statoState

Modifica di alcuni passi

in una proceduraTemplate method

Creazione di oggetti diversi

ma correlati Factory method

Page 18: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Design pattern (GoF, 1994)

18

L’idea viene dall’architettura

(Christopher Alexander)

Soluzione tipica, provata sul

campo, a problemi ricorrenti

L’idea viene portata dentro l’ingegneria del software dalla

banda dei quattro (Erich Gamma, Richard Helm, Ralph

Johnson and John Vlissides) con il libro Design Patterns:

Elements of Reusable Object-Oriented Software

Riflessione critica su

ereditarietà e contenimento

Catalogo dei pattern

divisi in tre categorie

Page 19: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Perché parlarne ora?

19

Noi discutiamo i design pattern

(non i pattern architetturali)

Risolvono problemi su scala

“medio-piccola” (di classi)

Strutture consolidate

dall’esperienza

Idee per il codice nuovo,

ma anche per il refactoring

Forniscono un linguaggio di

alto livello molto diffuso

Aiutano a capire la struttura e la

documentazione del software

Enorme valenza culturale per chiunque scriva software,

oppure debba interagire con grandi sistemi (CMSSW)

Page 20: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Struttura di un pattern

20

Ci sono vari modi per

implementare un certo pattern

È l’idea che lo definisce,

non il diagramma delle classi!

1. Nome (breve e comunicativo):

Alza il livello della discussione e della documentazione.

2. Il problema da risolvere:

Sintomi di un design rigido, condizioni da rispettare.

3. La soluzione:

Costituenti, relazioni, responsabilità e collaborazioni.

4. Le conseguenze:

Bilancio costi/benefici, impatto sul riuso, implementazioni.

Un pattern cattura la “saggezza” accumulata

Page 21: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

L’introduzione vale il libro

21

2. Program to an interface, not an implementation

Non appoggiarsi al fatto che la classe

derivata eredita tutto il codice ed i dati

1. Separate things that change from things that stay the same

Posizionare interfacce tra la parte

stabile e quella che cambia (OCP)

3. Favor object composition over class inheritance

L’ereditarietà è statica, ed espone più

dettagli del semplice contenimento

Page 22: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Il catalogo (23 pattern)

22

Creazionali

Come posso creare gli oggetti

concreti se conosco solo le

interfacce astratte?

Strutturali

Come conviene combinare

classi (ereditando) ed

oggetti (componendo)?

Comportamentali

Come far interagire gli oggetti,

distribuendo bene le

responsabilità tra di essi?

Page 23: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Strategy (policy)

23

Lo stesso compito può essere

eseguito in modi diversi

Dobbiamo poter sostituire

gli algoritmi, anche a runtime

Context contiene un puntatore di

tipo Strategy (interfaccia)

Classi concrete con

i vari algoritmi

Page 24: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Ricostruzione delle tracce

24

const OrderedSeedingHits& triplets = theGenerator->run(region,ev,es);

unsigned int nTriplets = triplets.size();

for (unsigned int iTriplet = 0; iTriplet < nTriplets; ++iTriplet) {

const SeedingHitSet& triplet = triplets[iTriplet];

std::vector<const TrackingRecHit *> hits;

for (unsigned int iHit = 0, nHits = triplet.size(); iHit < nHits; ++iHit) {

hits.push_back( triplet[iHit]->hit() );

}

reco::Track* track = theFitter->run(es, hits, region);

if( theFilter && !(*theFilter)(track, hits) ) {

delete track;

continue;

}

tracks.push_back(TrackWithTTRHs(track, triplet));

}

theGenerator->clear();

theGenerator,

theFitter e theFilter

sono puntatori di

tipo classe astratta

Page 25: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Adapter (wrapper)

25

A volte un oggetto non ha

il “guscio giusto”

Ereditiamo dall’interfaccia

corretta, ed incapsuliamo

Interfaccia corretta

Ereditarietà privata

o contenimento

Adattatore

(classe o oggetto)

Classe vecchia che

vogliamo riciclare

Request gira

il messaggio

Page 26: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Decorator

26

Voglio fare le stesse cose,

ma con un passo in più

Eredito, e sposto le decorazioni

in una classe separata

Il decorator (astratto) eredita da

component, e contiene un

puntatore a component (astratto)

In Operation(), chiamo la

Operation() del decorator, e poi

aggiungo gli abbellimenti

Page 27: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Template method

27

Sequenza fissa di operazioni,

ma alcuni passi variano

Isoliamo lo scheletro, e

ridefiniamo i singoli passi

Classe base:

TemplateMethod

(concreto) definisce

la sequenza virtual or

pure virtual

Classe derivata:

sovrascrive i

singoli passi

Page 28: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Template method: un esempio

28

void VirtualJetProducer::produce(edm::Event& iEvent,

const edm::EventSetup& iSetup)

{

edm::Handle<reco::CandidateView> inputsHandle;

iEvent.getByLabel(src_, inputsHandle);

for(size_t i=0; i<inputsHandle->size(); ++i) {

inputs_.push_back( inputsHandle->ptrAt(i) );

}

fjInputs_.reserve( inputs_.size() );

inputTowers();

runAlgorithm( iEvent, iSetup );

output( iEvent, iSetup );

}

Virtuale pura: passo della

procedura che può (deve)

cambiare nelle classi derivate

Template

Method

Page 29: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Iterator

29

Devo accedere agli elementi di

un contenitore in sequenza

Voglio essere indipendente

dalla struttura del contenitore

Inizio, fine,

elemento corrente,

prossimo elemento

Nelle STL, disaccoppio

contenitori ed algoritmi

Page 30: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Dipendenze di creazione

30

Il nostro codice dipende solo

dalle interfacce (astratte)

Prima o poi, dobbiamo creare le

istanze di classi concrete

?

void BaseClass::run()

{

IOStrategy* s = new IOFromFile();

std::vector<double> ptVec;

s->read( ptVec );

s->write( ptVec );

}

Qui siamo isolati dal modo

in cui leggiamo/scriviamo

il vettore (estensibilità)

Anche se implemento nuove

strategie, e/o derivo da BaseClass,

viene creata sempre IOFromFile

Page 31: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Factory method

31

Elimino le chiamate dirette a

new (non ridefinibile)

Sposto il new dentro una

funzione che crei gli oggetti

Creo i sotto-oggetti

mediante una

funzione virtual

Posso ridefinire la

funzione, e creare

oggetti di tipo nuovo

Page 32: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Sintesi della quarta puntata

32

• Refactoring:

– Come far evolvere il codice.

– In che direzione andare.

– A che livello agire.

• Design pattern (GoF):

– Che cosa sono.

– Perché parlarne.

– Qualche esempio.

Page 33: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Pensieri finali

33

Non si diventa esperti di OOP

in 7-8 ore di lezione

Abbiamo toccato e discusso

gli aspetti fondamentali

Tuttavia…

Di strada insieme ne abbiamo fatta parecchia:

dal C alle classi, all’ereditarietà, al polimorfismo, ai pattern

Quanto detto dovrebbe servire

sia ad inquadrare la filosofia,

sia come linea guida pratica

Volutamente abbiamo mischiato

teoria e codice, concetti di base

e problemi sofisticati

Page 34: Programmazione Object-Oriented per utenti di CMSSWcms.pd.infn.it/tutorials/ProgObjOriented/OOP_4.pdfSpostare variabili e metodi da una classe all’altra. 4. Organizzare i dati (cont.

Conclusione

34

Bjarne Stroustrup. The C++ Programming Language, pp. 692 :

Design and programming are human activities; forget that and all is lost.

Il codice deve comunicare

subito che cosa fa

Un codice ben strutturato abbrevia decisamente

il cammino verso la pubblicazione!

Il sistema deve poter essere

esteso facilmente