Il Composite è un pattern fondamentale definito dalla GoF e rappresenta un modo semplice di aggregazione e gestione dei gruppi di oggetti simili in modo che per un client un singolo oggetto sia indistinguibile da un insieme di oggetti.
Categoria: PHP
Uno dei principi cardine della programmazione ad oggetti è sicuramente:
Programmare verso l’interfaccia non verso l’implementazione.
(Program to an interface, not an implementation)
Ereditarietà vs Composizione
Una delle attività fondamentali in un progetto orientato agli oggetti è stabilire rapporti tra le classi. Due modi di mettere in relazione le classi sono l’ereditarietà e la composizione.
Questo post ha come obiettivo mettere a confronto i precedenti due approcci ed eventualmente cercare di capire se uno è preferibile all’altro.
Ereditarietà
Non vi è dubbio che l’ereditarietà (detta anche specializzazione) è un potente strumento di progettazione per mutare le circostanze o i contesti. Si tratta di un meccanismo supportato direttamente dal linguaggio, il che si traduce in una notevole semplicità nel creare gerarchie di classi.
Tuttavia si dovrebbe anche considerare che l’ereditarietà crea una relazione statica definita a compile-time ed infrange il principio dell’incapsulamento creando una forte dipendenza nelle gerarchie.
Pro:
- E’ facile da usare essendo parte del linguaggio
- Si applica a tutti i metodi della classe (non è possibile ereditare solo una parte degli attributi e dei metodi)
- Facilita il riutilizzo del codice consentendo alla sottoclasse di riutilizzare il codice della superclasse. Difatti se la classe figlio non esegue l’override del metodo potrà “riutilizzare” quello della classe genitore (senza riscriverlo).
- Permette il polimorfismo (interfaccia unica ma comportamenti specifici diversi)
Contro:
- E’ rigida, il comportamento è fissato al tempo di compilazione, creando così una relazione statica tra le classi.
- Può portare alla creazione di gerarchie di classi “mostruose” che finiscono quasi sempre nel diventare ingestibili.
- Viola il principio dell’incapsulamento: le classi figlie vedono quello che c’è nella classe padre (una modifica nella classe padre può avere conseguenze sulle classi figlio). In questo caso si dice che la classe figlio è “debolmente incapsula”.
L’ultimo punto è particolarmente “pericoloso”. Se si modifica la classe padre si rischia di dover riadattare anche tutte le classi figlio. Una teoria diffusa è quella di ereditare unicamente da classi astratte.
[box type=”note”]Da ricordare che in PHP (a differenza di altri linguaggi OOP) una classe può avere un solo genitore, non è supportata alcuna forma di eredità multipla.[/box]
Composizione
Come abbiamo visto, la relazione di ereditarietà rende difficile cambiare l’interfaccia di una classe padre, dato che questo si ripercuoterà su tutte le classi figlio che andrebbero riadattate. Vale quindi la pena guardare un approccio alternativo, fornito dalla composizione.
La composizione prevede un approccio che rende più facile la modifica del codice.
La composizione ci offre un grande vantaggio, l’oggetto componente è accessibile unicamente attraverso la sua interfaccia, in questo modo non si viola il principio dell’incapsulamento.
Pro:
- E’ dinamica, ogni oggetto può essere rimpiazzato a run-time con un’altro oggetto che abbia la stessa interfaccia (sia dello stesso tipo).
- Non viola il principio dell’incapsulamento, (dato che viene esposta soltanto l’interfaccia).
- Evita la costruzione di gerarchie classi mostruose ed ingestibili.
Contro:
- E’ meno semplice scrivere codice rispetto all’ereditarietà pura.
- Il codice dinamico è più difficile da comprendere respetto ad uno più statico.
- Porta ad un aumento del numero degli oggetti.
Dal punto di vista della dipendenza possiamo anche affermare che la composizione porta alla creazione di due oggetti, mentre attraverso l’ereditarietà l’oggetto in esecuzione è uno solo.
Riutilizzo
Sia l’ereditarietà che la composizione sono due tecniche comuni riguardo al riuso di funzionalità (di codice quindi) nei sistemi ad oggetti.
Il riutilizzo attraverso le sotto classi è definito white-box. Il termine si riferisce alla visibilità del codice. Come detto le classi figlio nella maggior parte dei casi sono in grado di vedere la struttura interna delle classi padre, violando così il principio dell’incapsulamento.
Il riuso definito attraverso la composizione e detto black-box. Gli oggetti appaiono come scatole nere, i dettagli implementativi non sono visibili ma e visibile soltanto l’interfaccia.
Quale utilizzare?
Dal punto di vista didattico/teorico si dovrebbe sceglie tra ereditarietà e composizione in base alle relazioni che vengono espresse.
In una relazione is-a si dovrebbe preferire l’ereditarietà.
In una relazione has-a invece sarebbe preferibile la composizione.
Quindi se:
- Un oggetto di
B
è un (is-a) oggetto diA
-> ereditarietà. - Un oggetto di
B
ha un (has-a) oggetto diA
-> composizione.
Ancora:
- Se tutti i metodi della classe
A
devono essere metodi anche diB
allora si usa l’ereditarietà. - Se alcuni metodi della classe
A
non devono essere metodi anche diB
allora si usa la composizione.
Da eredità a composizione
Vediamo ora l’ereditarietà al lavoro, l’impiegato è una persona ed eredita da questa:
class Person { private $_firstName; private $_lastName; private $_age; public function getFullname() { return $this->_firstName . ' ' . $this->_lastName; } } class Employee extends Person { private $_company; private $_salary; }
Tuttavia, fregandocene della più logica relazione is-a, ecco come possiamo spostare il precedente esempio a favore delle composizione:
class Person { private $_firstName; private $_lastName; private $_age; public function getFullname() { return $this->_firstName . ' ' . $this->_lastName; } } class Employee { private $_person; private $_company; private $_salary; public function __construct(Person $person) { $this->_person = $person; } public function getFullName() { $this->_person->getFullname(); } }
In questo esempio l’impiegato non eredita da una persona ma ottiene invece un oggetto Person
passato tramite il costruttore (Dependency Injection). Dal punto di vista delle relazioni l’impiegato non “è una” persona ma “ha una” persona.
[box type=”note”]Il meccanismo che fa si che la composizione diventi un’alternativa all’ereditarietà riguardo al riuso del codice è detto Delega. Con la delega, come abbiamo visto, l’oggetto che riceve la richiesta delaga la risposta al proprio delegato (nell’esempio Employee
delega la risposta a Person
).[/box]
Conclusioni
Sia composizione che ereditarietà sono due “meccanismi” strettamente legati al tentativo di risolvere il problema del riutilizzo del codice (evitandone cioè la duplicazione).
Se il tuo intento e’ quello di riutilizzare parte del codice di una classe, invece che estenderla, sarebbe meglio utilizzare la composizione includendo nell’interfaccia solo i metodi per cui vuoi
delegarne l’implementazione.
Personalmente ho imparato a preferire quasi sempre la composizione rispetto all’ereditarietà. Non c’è nessun problema di programmazione risolvibile con l’eredità che non si possa risolvere con la composizione.
La composizione offre una migliore astrazione, migliore incapsulamento, elimina un sacco di complessità e diminuisce drasticamente la probabilità di rompere qualcosa da qualche parte quando si esegue una modifica nel codice.
Non ci sono spetti negativi nella composizione ed esclusione del fatto che saremo costretti a scrivere qualche riga in più di codice.
L’ereditarietà con il passare del tempo tende elevare la complessità, il codice diviene difficile da cambiare, mantenere, e scalare senza errori.
Quindi:
- Prima di usare l’ereditarietà, valutare se la composizione ha più senso.
- Se quello che si vuole veramente è riutilizzare il codice, utilizzare sempre la composizione.
- Quando ci si trova davanti al dubbio se scegliere ereditarietà o composizione, scegliere senz’altro quest’ultimo tipo di relazione.
PHP 5.4 – I Traits guida completa
Il problema della duplicazione del codice è sicuramente alla base delle migliori tecniche di programmazione. Il codice duplicato rende la manutenzione del software più difficile, perché ogni codice duplicato deve essere mantenuto costante, e un bug che è stato trovato sul codice duplicato non può essere fixato in un solo punto.
PHP – Closure e funzioni anonime
A partire dalla versione 5.3, anche PHP dispone della possibilità di creare funzioni senza dichiararne il nome.
Le funzioni anonime (conosciute anche con il nome di lambda functions) e le closures (chiusure) permettono di fare proprio questo.
PHP – Basi sulla Dependency Injection
Probabilmente uno dei più grandi e “moderni” problemi delle programmazione OOP sono le dipendenze.
Se desideriamo scrivere codice di buona qualità, (quindi buone applicazioni) si dovrebbe limitare il più possibile gli effetti delle dipendenze tra le nostre classi.
PHP dispone di un certo un mero di funzioni dette “metodi magici“. Si tratta di metodi che vengono attivati al verificarsi di terminati eventi, ed aventi una sintassi particolare nel nome. Difatti li possiamo riconoscere facilmente visto che iniziano tutti con un doppio undescore.
Qualche giorno fa ho aggiunto sulla sezione video di Ariete il numero di visualizzazioni dei video presenti sul canale YouTube (total Upload Views).
E finalmente venne il giorno!!!
Per motivi di tempo ho sempre rimandato l’aggiornamento del mio XAMPP ma ora basta… è giunto il momento di passare a PHP 5.4… anche se per dire la verità le sue novità le avevo già abbondantemente provate con il suo built-in web server.
PHP -Design Pattern Factory Method
Nella programmazione OOP quando si parla di pattern ci si riferisce semplicemente alle pratiche migliori per risolvere un determinato e noto problema. Ciò significa che anche se è possibile risolvere il problema con metodi alternativi, un pattern sarà il modo più efficace per raggiungere l’obiettivo.