Introduction to
Object-Oriented
Programming
in C++
Vincenzo Innocente
CERN, Geneva, Switzerland
Vincenzo Innocente
1
Programmazione procedurale
• Uno dei principali problemi del
software è la sua evoluzione e la
sua manutenzione
– specialmente in grossi progetti come
un esperimento di HEP
• Esempi con linguaggi
procedurali (Fortran):
– Cosa succede quando il codice viene
modificato
– Dipendenze all’interno del codice
Vincenzo Innocente
2
C++/Object Oriented
• Riduce la dipendenza del codice
di alto livello dalla
rappresentazione dei dati
Permette il riutilizzo del codice
di alto livello
• Nasconde i dettagli di
implementazione
Vincenzo Innocente
3
Classi e oggetti
• Definizione di nuovi tipi (oltre a int,
float, double) come:
– numeri complessi,
– vettori,
– matrici, . . .
• ma anche:
–
–
–
–
tracce,
superfici,
elementi di rivelatori,
cluster, . . .
• Gli oggetti permettono di modellare una
problema che rappresenti la realtà
Vincenzo Innocente
4
Concetti base dell’OO
•
•
•
•
Classi ed oggetti
Incapsulamento
Relazione di ereditarietà
Polimorfismo
• Programmazione Generica
(C++)
Vincenzo Innocente
5
Puntatori
• Riferimento ad una locazione di
memoria
#include <iostream.h>
int main()
{
int j = 12;
int *ptr = &j;
ptr
cout << *ptr << endl;
j = 24;
cout << *ptr << endl;
cout << ptr << endl;
j
24
12
return 0;
}
12
24
0x7b03a928
indirizzo di memoria
Vincenzo Innocente
6
Puntatori
• Puntatore nullo
#include <iostream.h>
ptr
j
12
int main()
{
int j = 12;
int *ptr = 0;
cout << *ptr << endl; //
crash !
return 0;
}
Segmentation violation (core dumped)
Vincenzo Innocente
7
Puntatori: allocazione dinamica
• Riferimento ad una locazione di memoria
#include <iostream.h>
int main()
{
int *ptr = new int;
ptr
12
*ptr = 12;
cout << *ptr << endl;
delete ptr;
return 0;
}
• Attenzione:
– Non usare delete fa accumulare locazioni di
memoria inutilizzate (memory leak)
– Utilizzare puntatori prima del new o dopo il
delete causa il crash del programma
Vincenzo Innocente
8
Classi e Oggetti
•
Un esempio di programma “orientato ad
oggetti”: un videogioco
Vincenzo Innocente
9
Cliente
Soldato
Vincenzo Innocente
10
Class Vector
• An example: un tri-dimentional vector
• With respect to a structure, a class contains
functions beside data
Vector.h
class Vector
{
public:
Vector(double x, double y, double z);
Vector(Vector& v);
double x();
double y();
double z();
double r();
double phi();
double theta();
protected:
double _x, _y, _z;
};
constructor
functions or methods
data
Vector.cc
#include “Vector.h”
Vector::Vector(double x, double y, double z) :
_x(x), _y(y), _z(z) {}
copy constructor
Vector::Vector(Vector& v) :
_x(v.x()), _y(v.y()), _z(v.z()) {}
double Vector::x()
{ return _x; }
double Vector::r()
{ return sqrt(_x*_x + _y*_y + _z*_z); }
Vincenzo Innocente
11
Class Vector
• How to use Vector:
main.cc
#include <iostream.h>
#include “Vector.h”
invoke the constructor
int main()
{
Vector v(1, 1, 0);
cout <<
<<
<<
<<
cout <<
cout <<
“ v = (“
v.x() << “,”
v.y() << “,”
v.z() << “)” << endl;
“ r = “ << v.r();
“ theta = “ << v.theta() << endl;
}
Output:
v = (1, 1, 0)
r = 1.4141 theta = 1.5708
Vincenzo Innocente
12
Class Vector
• Data access protection:
main.cc
#include <iostream.h>
#include “Vector.h”
int main()
{
Vector v(1, 1, 0);
cout <<
<<
<<
<<
cout <<
cout <<
“ V = (“
v._x << “,”
//
v._y << “,”
// does not
v._z << “)” << endl; // compile !
“ r = “ << v.r();
“ theta = “ << v.theta() << endl;
}
Vincenzo Innocente
13
Interface and implementation
• Protected data are not accessible
outside the class
Vector.hh
class Vector
{
public:
Vector(double x, double y, double z);
double x() const;
double y() const;
double z() const;
double r() const;
double phi() const;
double theta() const;
protected:
double _x, _y, _z;
};
const
Vector.cc
#include “Vector.h”
Vector::Vector(double x, double y, double z) :
_x(x), _y(y), _z(z)
{}
double Vector::x() const
{ return _x; }
double Vector::r() const
{ return sqrt(x*x + y*y + z*z); }
Vincenzo Innocente
14
Interface and implementation
• The internal structure of the
data (_x, _y, _z) that represent
the objects of the class Vector
are hidden (protected) to the
clients of the class.
• The clients do not depend on
the internal structure of the data
(as it was the case for clients of
FORTRAN common block)
• If the internal structure changes
(es.: _r, _theta, _phi), the
code using Vector does not
have to be modified.
Vincenzo Innocente
15
Operators
• It is possible to redefine +, -, *, [],
++, ==, . . .
Vector.hh
class Vector
{
public:
Vector(double x, double y, double z);
double x() const;
double y() const;
double z() const;
double r() const;
double phi() const;
double theta() const;
Vector operator+(const Vector& v) const;
Vector operator-(const Vector& v) const;
protected:
double _x, _y, _z;
};
Vector.cc
Vector Vector::operator+(const Vector& v) const
{
return Vector(_x + v._x, _y + v._y, _z + v._z);
}
Vector Vector::operator-(const Vector& v) const
{
return Vector(_x - v._x, _y - v._y, _z - v._z);
}
Vincenzo Innocente
16
Operators
• Example:
main.cc
#include <iostream.h>
#include “Vector.h”
int main()
{
Vector v1(1, 0, 0), v2(0, 1, 0);
Vector v;
redefinition of <<
v = v1 + v2;
cout << “ v = “ << v << endl;
cout << “ r = “ << v.r();
cout << “ theta = “ << v.theta() << endl;
}
Output:
v = (1, 1, 0)
r = 1.4141 theta = 1.5708
Vincenzo Innocente
17
Operators
• Example:
main.cc
#include
#include
#include
#include
<iostream.h>
<math.h>
“Vector.h”
“Matrix.h” // matrix 3x3
int main()
{
Vector v1(1, 1, 0);
p
double phi = M_PI/3;
double c = cos(phi), s = sin(phi);
Matrix m(1, 0, 0,
0, c, s,
0, -s, c);
Vector u = m * v;
}
Vincenzo Innocente
18
Operator overloading
• It is possible to define functions with the
same name but different arguments
Vector.hh
class Vector
{
public:
...
Vector operator*(double s) const;
double operator*(const Vector& v) const;
protected:
double _x, _y, _z;
};
Vector.cc
Vector Vector::operator*(double s) const
{
return Vector(_x *s, _y *s, _z *s);
}
double Vector::operator*(const Vector& v) const
{
return (_x * v._x + _y * v._y + _z * v._z);
}
Vincenzo Innocente
19
Static Functions and data
• Some functions can be common to the whole class
Particle.h
class Particle
{
public:
Particle(int code, double mass, int charge);
int code() const { return _code; };
double mass()
{ return _mass; };
int charge()
{ return _charge; };
static int numberOfParticles();
protected:
double _mass;
int _code, _charge;
static int _n;
};
Particle.cc
#include “Particle.h”
int Particle::_n = 0;
Particle::Particle(int code,
double mass, int charge) :
_code(code), _mass(mass), _charge(charge)
{ _n ++; }
int Particle::numberOfParticles()
{ return _n; }
Vincenzo Innocente
20
Classi astratte
• Esempio
classico:
Shape
•
Tutti oggetti nella
finestra hanno
comportamenti
comuni che possono
essere considerati in
astratto:
– disegna,
sposta,
ingrandisci,
etc.
Vincenzo Innocente
21
Ereditarietà e riuso del codice
CenteredShape.h
Class CenteredShape: public Shape
{
public:
CenteredShape( Point2d c )
: center_( c )
{ /*draw();*/ }
~Circle()
{ /*cancel();*/ }
Non si possono
chiamare metodi
virtuali in costruttori e
distruttori (troppo
presto, troppo tardi)
void moveAt( const Point2d& );
void moveBy( const Vector2d& );
virtual void scale( double ) =
Square.h
0;
virtual void rotate( double
) =
#include
“CenteredShape.hh”
0;
virtual void draw() const class
= 0; Square : public CenteredShape
virtual void cancel() const
{ =
0;
public:
Square( Point2d lowerCorner, Point2d
protected:
upperCorner ) :
Point2d center_;
CenteredShape( median(lowerCorner,
};
upperCorner) ),
touc_(upperCorner - center_) { draw(); }
~Square() { cancel(); }
virtual void scale( double s )
{ cancel(); centerToUpperCorner_ *= s;
draw(); }
virtual void rotate( double phi );
virtual void draw() const;
virtual void cancel() const;
private:
Vector2d touc_;
};
Vincenzo Innocente
22
Quadrato
Square.cc
Square.h
#include “Square.h”
class Square {
public:
Square(const Point2d&, const
Point2d&);
~Square();
void moveAt( const Point2d&
p );
void moveBy( const Point2d&
p );
void scale( double s );
void rotate( double phi );
void draw() const;
void cancel() const;
private:
Point2d center_;
Vector2d
centerToUpperCorner_;
};
void Square::rotate( double phi )
{
cancel();
centerToUpperCorner_.rotate( phi
);
draw();
}
centerToUpperCornerupperCorner
_
loweCorner
void Square::draw() const
{
float x[4], y[4];
Vector2d delta(
centerToUpperCorner_ );
for ( int i = 0; i < 4; i++ )
{
Point2d corner = center_ +
delta;
x[i] = corner.x();
y[i] = corner.y();
delta.rotate( M_PI_2 );
}
polyline_draw(x, y, 4);
}
Square::Square(const Point2d&
lowerCorner,
const Point2d&
upperCorner ) :
center_( median(lowerCorner,
upperCorner) ),
centerToUpperCorner_( upperCorner
- center_ )
{ draw(); }
void Square::scale( double s )
{ cancel(); centerToUpperCorner_
*= s; draw(); }
Vincenzo Innocente
23
Cerchio
Nome della classe
Circle.h
Circle.cc
Costruttore
class Circle {
public:
#include “Circle.h”
Circle(Point2d center, double radius);
~Circle();
void Circle::draw() const
{
void moveAt(const Point2d & p);
const int numberOfPoints = 100;
void moveBy(const Point2d & p);
float x[numberOfPoints],
void scale(double s);
Point2d: classe che rappresenta
y[numberOfPoints];
void rotate(double phi);
float phi = 0, deltaPhi = 2*M_PI/100;
un punto in 2 dimensioni.
void draw() const;
for ( int i = 0; i < numberOfPoints;
void cancel() const;
++i )
{
private:
x[i] = center_.x() + radius_ *
Point2d center_;
cos( phi );
}; double radius_;
y[i] = center_.y() + radius_ *
sin( phi );
phi += dphi;
}
polyline_draw(x, y, numberOfPoints );
}
Distrutt
ore
Main.cc
Interfaccia Pubblica
Metodi: operazioni
sugli oggetti
void Circle::moveAt( const
#include “Circle.h”
int main()
{
{
cancel(); center_ = p;
Circle c( Point2d(10, }
“Dati” privati
10), 5 );
c.draw();
c.moveAt(Point2d(20,
30));
Punto e virgola!
return 0;
}
void Circle::scale( double
(Attributi,
{
membri)
cancel(); radius_ *= s;
Point2d& p )
draw();
s )
draw();
}
Circle::Circle( Point2d c, double r ) :
center_( c ), radius_( r )
{ draw(); }
Circle::~Circle()
{ cancel(); }
Vincenzo Innocente
24
Codice Applicativo (Client)
Main.cc
#include “Circle.h”
#include “Square.h”
int main()
{
Circle c1( Point2d(2.,3.), 4.23, );
Square r1( Point2d(2.,1.),
Point2d(4.,3.) );
Circle * circles[ 10 ];
for ( int i = 0; i < 10; ++i )
{
circles[ i ] = new Circle(
Point2d(i,i), 2. );
}
Costruisce un vettore di
puntatori a cerchi, crea
oggetti in memoria e salva i
loro puntatori nel vettore.
for ( int i = 0; i < 10; ++i )
circles[ i ]->draw();
return 0;
}
Itera sul vettore e invoca draw()
per ogni elemento
Come gestire
cerchi
e quadrati
insieme?
Vincenzo Innocente
25
Programmazione generica
Funzioni Generiche
“<” deve essere definito
per “T”
template<class T>
inline T min(const T& a, const T& b)
{ return a < b ? a:b; }
Main.cc
P.h
Usa min<float>
class P {
public:
P(int ix,int
iy):x(ix),y(iy){}
int main() {
float a = min(3.,2.);
int i = min(2,3);
bool operator<(const P& b)
const {
return y<b.y ||( y==b.y
&& x<b.x );
}
private:
float x;
float y;
};
P p1(1.,2.),
p2(3.,1.);
P p3 = min(p1,p2);
return 0;
}
Vincenzo Innocente
Usa min<P>
26
Programmazione generica
Classi Generiche
“copy” è una funzione generica
di STL
Vector3d.h
template <class T>
class Vector3d {
public:
Vector3d(const T*a) {
copy(a,a+3,&x[0]); }
Vector3d<T>& operator+=(const
Vector3d<T>& b)
{x[0]+=b.x[0]; x[1]+=b.x[1];
x[2]+=b.x[2];
return *this;}
private:
T x[3];
};
Ritorna se stesso per permettere
la concatenazione di operatori
Vincenzo Innocente
Main.cc
#include
“vector3d.h”
int main() {
Vector3d<float> a,
b,c;
c+=b+=a;
Vector3d<complex>
c1, c2;
c2+=c1;
return 0;
}
27
La libreria standard: std (STL)
• Contenitori generici:
– vector, list, set, map,
“string”
• Iteratori
– puntatori “intelligenti” nei
contenitori generici
• Funzioni generiche
– copy, merge, find, sort, swap,…
– agiscono su iteratori
Vincenzo Innocente
28
Un semplice vettore
Main.cc
#include <vector>
int main() {
vector<int> v;
di interi vuoto
cout << v.size() << endl;
di v: zero
for ( int i = 0; i != 10; ++i )
v.push_back( i );
intero in coda a v
// creamo un vettore
// stampa dimensione
// un loop da 0 a 9
// aggiungiamo un
cout << v.size() << endl;
// stampa dimensione
di v: 10
// creiamo un iteratore costante per
un vettore di interi:
// p si comporta come un “const int
*” a tutti gli effetti
vector<int>::const_iterator p;
for ( p = v.begin(); p != v.end(); ++p ) // “itera
dall’inizio alla fine di v”
cout << (*p) << “ “;
cout << endl;
return 0;
}
Vincenzo Innocente
29
Un semplice vettore
begin()
end()
0 1 2
p
p
p
...
9
p
Vincenzo Innocente
p
p
30
Vettore di classe astratta Shape*
Main.cc
#include “Circle.h”
#include “Square.h”
#include <vector>
int main()
{
vector<Shape *> vs; // un vettore di puntatori a Shapes
for ( int i = 0; i != 10; ++i )
{
// aggiungiamo un puntatore ad un nuovo cerchio
vs.push_back(new Circle(Point2d(i, i), 2.));
// aggiungiamo un puntatore ad un nuovo quadrato
vs.push_back(new Square(Point2d(i, i), Point2d(i + 1, i +
2)));
}
// iteratore: essenzialmente un puntatore a Shape* ossia un
Shape**
vector<Shape *>::const_iterator p;
for ( p = vs.begin(); p != vs.end(); ++p ) // loop
sull’intero vettore
(*p)->draw(); // disegniamo ogni Shape
return 0;
}
Vincenzo Innocente
31
Interfaccia astratta
Shape.h
class Shape {
public:
Shape() { }
virtual ~Shape() { }
virtual
) = 0;
virtual
virtual
0;
virtual
virtual
};
Main.cc
void moveAt( const Point2d&
#include “Circle.h”
void scale( double s ) = 0;
#include “Square.h”
void rotate( double phi ) =
int main()
void draw() const = 0;
{
void cancel() const = 0;
Shape * shapes[ 10 ];
int index = 0;
for ( int i = 0; i < 10; i++ )
{
Shape * s;
s = new Circle( Point2d(i, i),
2.) );
shapes[ index ++ ] = s;
s = new Square( Point2d(i, i),
Point2d(i+1,
i+2)) );
shapes[ index ++ ] = s;
}
Interfaccia di
metodi
puramente
virtuali
Square.h
for ( int i = 0; i < 10; i++ )
shapes[ i ]->draw();
return 0;
}
#include “Shape.h”
class Square : public Shape
{
// …. Il resto tutto
uguale a prima
};
Vincenzo Innocente
32
Superfici e traiettorie
• Nel tracking spesso è necessario calcolare
intersezioni tra curve (tracce) e superfici
(elementi di detector)
Intersection
Trajectory
Surface
Line
Plane
PolyLine
Cylinder
Helix
Vincenzo Innocente
33
Superfici e traiettorie
• Interfaccia delle diverse Trajectory
Trajectory.h
Line.h
class Trajectory
{
public:
virtual Point position(double
s) = 0;
virtual Vector
direction(double s) = 0;
};
#include “Trajectory.h”
class Line : public Trajectory
{
public:
virtual Point position(double
s);
virtual Vector
direction(double s);
public:
Point origin_;
Vector direction_;
};
Helix.h
#include “Trajectory.h”
class Helix : public
Trajectory
{
public:
virtual Point
position(double s);
virtual Vector
direction(double s);
};
Vincenzo Innocente
34
Superfici e traiettorie
• Implementazione
Trajectory.cc
#include
“Trajectory.h”
Helix.cc
// … vuoto ...
#include “Helix.h”
Helix::Helix()
{
}
Line.cc
#include “Line.h”
Line::Line(const Point& o,
constVector& d) :
origin_( o ), direction_(
d.unit() )
{
}
Point
Helix::position(double
s)
{
// implementazione
}
Point Line::position(double s)
{
return ( origin_ + s *
direction_ );
}
Vincenzo Innocente
35
Superfici e traiettorie
• Interfaccia delle varie Surface
Surface.h
distanza (con segno) di un punto
dalla superficie
class Surface
{
public:
virtual distance(const Point& p) = 0;
virtual derDist(const Point& p, const
Vector& r) = 0;
};
Plane.h
#include “Surface.h”
class Plane : public Surface
{
public:
virtual distance(const
Point& p);
virtual derDist(const
Point& p,
const
Vector& r);
protected:
Point origin_;
Vector norm_;
double dist_;
};
Cylinder.h
#include “Surface.h”
class Cylinder : public
Surface
{
public:
virtual distance(const
Point& p);
virtual derDist(const Point&
p,
const
Vector& r);
};
Vincenzo Innocente
36
Superfici e traiettorie
• Surface è una classe astratta
Plane.cc
#include “Plane.h”
Surface.cc
#include “Surface.h”
// vuoto
Plane::distance(const Point& p)
{
return ( _dist - ( (p - origin_) *
direction_) );
}
Plane::derDist(const Point& p,
const Vector& r)
{
Cylinder.cc
return - r * _direction;
}
#include “Cylinder.h”
Cylinder::distance(const Point&
p)
{ /* . . . */ }
Cylinder::derDist(const Point&
p,
const Vector&
r)
{ /* . . . */ }
Vincenzo Innocente
37
Superfici e traiettorie
• Interfaccia di Intersection
Intersection.h
forward class declaration
class Surface;
class Trajectory;
class Intersection
{
public:
Intersection(Surface* s, Trajectory*
t)
surface_(s), trajectory_(t) {}
Point intersect(double s1, double
s2);
protected:
double sIntersect(double s1, double
s2);
Surface* surface_;
Trajectory* trajectory_;
};
Vincenzo Innocente
38
Superfici e traiettorie
Intersection.cc
#include
#include
#include
#include
• Implementazion
e dell’algoritmo
“Intersection.h”
<math.h>
“Surface.h”
“Trajectory.h”
const int maxIterations 20
const double sMax 1.e+6
const double accuracy1.e-3
// controlla che test è tra s1
double
Intersection::sIntersect(double
s1,
double s2)
{
// algoritmo di Newton-Raphson
double s = s1;
double maxS = max(s1, s2);
double minS = min(s1, s2);
double d, delta;
for( int j = 0; j <
maxIterations; j++ )
{
Point p = _trajectory>position( s );
d = surface_->distance( p );
delta = surface_->derDist( p,
trajectory_>direction( s ) );
double ds = - d / delta;
double test = s + ds;
e s2
if( (s1 - test) * (test - s2) <
0.0 )
{
if ( s1 < s2 ) s += abs( d );
else
s -= abs( d );
if( s > maxS || s < minS )
return sMax;
}
else s = test;
if( abs(d) < accuracy )
return s;
}
return sMax;
}
Point
Intersection::intersect(double s1,
double s2)
{
return
trajectory_>position(sIntersect(s1, s2));
}
Vincenzo Innocente
39
Superfici e traiettorie
• Intersection usa solo:
– I metodi position e direction di
un’oggetto Trajectory
– I metodi distance e derDist di un
oggetto Surface
• E’ possibile aggiungere una nuova
classe che modellizza una nuova
Trajectory o una nuova
Surface e Intersection
continua a funzionare senza
modificare una linea di codice!
• E’ possibile rendere anche
Intersection astratto...
Vincenzo Innocente
40
“Open/Closed principle”
• Un buon codice deve essere
– aperto ad estensioni
– chiuso a modifiche
• Modificare un codice
funzionante può introdurre
bachi…
• L’Object Oriented, con il
meccanismo delle classi
virtuali, permette di applicare
questo principio
Vincenzo Innocente
41
Conclusioni
• La programmazione C++
Object Oriented può aiutare a ridurre
le dipendenze all’interno del codice
e quindi lo sviluppo del programma
...
• … ma va utilizzato in maniera
adeguata, disegnando il codice prima
di implementarlo
• è facile scrivere un codice C++
traslitterando un codice F77, ma
questo non produce grandi
miglioramenti
Vincenzo Innocente
42
Unified Modeling Language
• Class Diagrams
• Sequence and Collaboration
Diagrams
• Use Case Diagrams
• State Diagrams
Vincenzo Innocente
43
UML Model of “Shape”
Vincenzo Innocente
44
Class Diagram
Vincenzo Innocente
45
Class Diagram
Vincenzo Innocente
46
Object Sequence Diagram
Vincenzo Innocente
47
Object Collaboration Diagram
Vincenzo Innocente
48
Design Patterns
E. Gamma et al., Design Patterns
“Elementi di software OO
riutilizzabile”
• Piccoli insiemi di classi che
collaborano implementando dei
comportamenti tipici
– Creational patterns
– Structural patterns
– Behavioral patterns
Alcuni pattern classici stanno diventanto
obsoleti grazie al supporto dei Template
Vincenzo Innocente
49
Factory
Client
I client possono
richiedere la
creazione di un
prodotto senza
dipendervi.
Factory
createProduct1 () :
AbstractProduct
createProduct2 () :
AbstractProduct
AbstractProduct La Factory
dipende dai
prodotti concreti,
mentre i client
dipendono solo
AbstractPro
duct.
ConcreteProduct1 ConcreteProduct2
Vincenzo Innocente
50
Singleton
Singleton
_instance : Singleton
if (_instance==0)
_instance = new Singleton()
instance () : Singleton
return _instance;
specificService ()
user_code()
{
Singleton::instance()>specificService(...);
}
Il Singleton pattern piò essere usato ogni volta che una classe deve essere
instanziata una sola volta, e viene usata da diversi oggetti.
Per evitare istanziazione accidentale, il constructor deve essere privato.
Più istanze, ma in numero ben determinato, possono esistere (multiton)
Siccome vengono usate funzioni statiche, l’ereditarietà non può essere
applicata.
Vincenzo Innocente
51
Template Singleton
Singleton
T
_instance
:T
if (_instance==0)
_instance = new T();
return _instance;
instance () : T
Singleton{V}
V
V( )
specificService( )
class V : public Singleton<V>
{
public:
specificService(...);
private:
V();
friend class Singleton<V>;
};
user_code()
{
V::instance()
->specificService(...);
}
Un Template Singleton
può essere specializzato
usando la classe stessa come
argomento del template.
Se V ha un constructor privato, Singleton<V> deve essere friend di V
(non tutti i compilatori lo supportano…).
Vincenzo Innocente
52
Proxy
Subject
Client
request( )
Proxy
RealSubject
request( )
_subject
1
1
_subject : RealSubject
request( )
Una richiesta da un client a un server,
...
può essere
_subject->request();
mediata dal Proxy, che può
...
compiere anche altre
operazioni (I/O, caching, etc.)
Vincenzo Innocente
53
Composite
Client
Component
operation( )
1..*
_children
Composite
Il client può trattare
componenti e
compositi usando la
stessa interfaccia.
La composizione
può essere
recursiva.
Leaf
operation( )
operation( )
for c in all _children
c->operation();
Vincenzo Innocente
Esempio:
programmi di
grafica vettoriale
54
Composite Shape
Client
Nel nostro esempio
di grafica con
Shapes un gruppo
può essere
considerato un
composito
e le varie classi
concrete
sono le leaves.
Shape
draw( )
1..*
_children
Gruppo
draw( )
Cerchio, Rettangolo, ...
draw( )
for c in all _children
c->draw();
Vincenzo Innocente
55
Strategy
Il pattern Strategy permette di
scegliere l’algoritmo da
eseguire a run-time.
{
...
Nuovi algoritmi possono essere
Strategy* s;
s->doAlgorithm(); introdotti senza modificare i
client.
...
}
Strategy
Client
doAlgorithm( )
ConcreteStrategyA ConcreteStrategyBConcreteStrategyC
doAlgorithm( )
doAlgorithm( )
Vincenzo Innocente
doAlgorithm( )
56
Observer
Observer
Subject
_observers
update( )
_observers : Observer
0..*
attach (Observer)
notify ()
for all o in _
observables
o->update();
ConcreteObserver
_status : Status
ConcreteSubject
_subject
_subject . ConcreteSubject
_status : Status
status( )
return _status;
Lo stato dell’Observer
dipende dallo stato del
Subject.
Il Subject notifica a
tutti gli Observer
registrati che il suo stato
è cambiato.
Vincenzo Innocente
update( )
_status =
_subject->status();
57
Visitor
Client
Visitor
visit1 (ConcreteElement1)
visit2 (ConcreteElement2)
Element
accept (Visitor)
ConcreteVisitor1
visit1 (ConcreteElement1)
visit1 (ConcreteElement1)
visit2 (ConcreteElement2)
visit2 (ConcreteElement2)
ConcreteElement1
ConcreteElement2
accept (Visitor v)
accept (Visitor v)
v->visit1(this)
v->visit2(this)
ConcreteVisitor2
Permette di aggiungere nuove
operazioni a Element senza
modificarne l’interfaccia.
Per aggiungere nuovi
ConcreteElement, bisogna
modificare tutti i Visitors.
Vincenzo Innocente
58
Scarica

int main()