Newsgroup: it.comp.www.php
Titolo: DAO vs Incapsulamento

Ciao
stavo dando una occhiata al pattern DAO e alle sue applicazioni. lo 
trovo molto comodo, solo ho dei dubbi.
Classi del genere non vanno contro il principio dell'incapsulamento?
<?php
class DO_User {
   public $userId;
   public $firstName;
   public $lastName;
   public $email;
   public function get($userId)
   {
     $sql = 'SELECT * FROM User WHERE userId='
			 . mysql_escape_string($userId);
     $rs  = mysql_query($sql);
     $row = mysql_fetch_array($rs);
     $this->userId  = $row['userId'];
     $this->firstName = $row['firstName'];
     $this->lastName  = $row['lastName'];
     $this->email   = $row['email']
   }
}
?>
Perchè è comodo prendere un campo con $classe->userId però non mi 
convince per quel che riguarda l'incapsulamento.
non sarebbe meglio (ma più laborioso) creare un get per ogni variabile 
relativa alla table (mettendole quindi private)?
Voi che ne pensate? Che è corretto comunque?
Grazie
-- 
Dott. Hellboy
MSN: 
simo...@hotmail.com
IChat: 
simo...@mac.com
http://www.hardboiled.it

 relativa alla table (mettendole quindi private)?
Dipende dai gusti, credo.
Io solitamente suddivido il DAO dall'oggetto. Il DAO mi rappresenta la
tabella nel DB, l'oggetto la singola riga
Quindi (semplificando la rappresentazione), dato DAO_Utente e Utente,
quando faccio un DAO_Utente->get_by_id($id) mi ritorna un oggetto
Utente, con le variabili pubbliche (odio abbastanza profondamente getter
e setter), e quando voglio salvare lo stato dell'oggetto in DB, faccio
un DAO_Utente->save(Utente) che se utente ha un id non nullo fa un
update, altrimenti un insert
Delego quindi a Utente tutte le funzioni che non necessitano di accesso
al DB (tipo controlli sui valori o roba del genere), e a DAO_Utente
quelle con accesso al DB (insert, update, delete, ecc.)
Forse rompe il paradigma dell'incapsulamento, ma con linguaggi altamente
dinamici come PHP (e in parte Python), lo trovo piu` semplice sia da
programmare che da usare.
Bye.
-- 
Alessandro Pellizzari

  
wrote:

Si, lo rompe.
Secondo alcuni, in ogni caso, anche una moltitudine di getter e setters  
rompe l'incapsulamento.
(con php5, poi, nel caso volessi cambiare successivamente la struttura  
interna della classe sopra, puoi riscriverla con i getter chiamare i  
getter/setter tramite __get e __set.
Ti segnalo un articolo di Fowler al proposito.
http://martinfowler.com/bliki/GetterEradicator.html
Concludendo, secondo me dipende dalla responsabilità che dai alla tua  
classe. Se la reponsabilità è contenere dati (vedi pattern Registry,  
DataSpace etc) l'uso di variabili pubbliche non è così drammatico.
Nel caso della classe sopra, le responsabilità sono almeno due: c'è anche  
il caricamento dei dati stessi. Questo è un problema noto del pattern a  
cui fai riferimento (che ad occhio e croce pare un active record).  
Nonostante questo, resta un pattern preferito da molti, per la sua  
semplicità, ad altri (come Table Gateway e via dicendo).
Tac
-- 
La netiquette prevede sign di al massimo quattro righe.
Purtroppo la mia sign in quattro righe non ci stà.

 update, altrimenti un insert
Separare DAO dall'oggetto è buona cosa per aggiungere ulteriore
granularità al software (pensiamo un giorno di voler supportare più
piattaforme db o comunque diverse sorgenti: avendo una classe DAO
apposita il lavoro è praticamente pronto), ma IMHO il modo con cui lo
associ all'oggetto che cui il programma avrà a che fare direttamente
presenta, sempre IMHO, due svantaggi:
1) Devo ricordarmi qual è la classe DAO, per ciascun tipo di oggetto
(utente, cliente, fornitore, fattura, ecc.) presente da cui prelevare i
dati;
2) Anche il salvataggio non è molto OOP, infatti sarebbe più
opportuna un'istruzione del tipo: Utente->save.
Quindi, io inserire la chiamata al DAO_Utente direttamente all'interno
della classe Utente, e quindi si manterrebbe contemporaneamente la
granularità del codice e soprattutto sarebbe più OOP, ovvero:
-------------------------------------------------------------
class Utente
{
           var $id;
           var $nome;
           ...
           ...
           function getUtenteById($id)
           {
                  $utenteTemp=DAO_Utente->getById($id);
                  // ora per riempire i campi dell'oggetto utente lo
puoi fare
                  // direttamente tramite reflection, per esempio
            }
            function save()
            {
                    DAO_Utente->save(this);
             }
}
----------------------------------------------------------------------
Inoltre l'utitlità di inserire funzioni getter e setter, come immagino
ben saprai, è molto comodo perchè se vuoi aggiungere dei controlli in
fase di raccolta o impostazione delle variabili puoi farlo. Farlo già
dall'inizio ti evita di dover di dover rimettere mano al codice in
futuro, se dovesse presentarsi l'esigenza di avere un controllo durante
azioni sulle variabili.
Ciao,
    Fabrizio

 azioni sulle variabili.
Lo so, e hai ragione. Solo che questo ti costringe a fare getter e
setter per tutto, mentre, sempre sfruttando PHP, posso aggiungerli in
seguito con __get e __set solo per le classi dove ne ho bisogno, e
mantenere il codice piu` pulito (IMO).
Ho notato (nel mio piccolo) che i programmatori Java tendono a
programmare come dici tu (getter, setter, azioni negli oggetti, ecc.),
mentre quelli python (che conosco molto meglio) tendono a evitare getter
e setter per fare come faccio io con l'overload delle primitive).
Bye.
-- 
Alessandro Pellizzari

Negus ha scritto:

Io però ho notato ,girando sul web, che la tendenza di questi pattern è 
di usare i Value Objects , in pratica delle classi senza metodi ma solo 
con variabili. Questi vanno a braccetto con i Data Access Objects .
Ora voglio provare a creare una classe tipo questa
class Tags{
	private $_id;
	private $_tagName;
 
	function __construct($id,$tagName){
		$this->_id = $id;
		$this->_tagName = $tagName;
	}
	public function get_id(){return $this->_id;}
	public function get_tagName(){return $this->_tagName;}
}
per poi creare un classe DA_tags tipo:
class DAO_tags{
	public function get($id);
	public function save(Tags $t);
}
tutto da implementare ovviamente..
poi aggiungerei un classe generica che gestisca il tutto, crei i loop 
per le tabelle.
Voglio trovare un bel manuale organico sui patterns, in giro trovo solo 
articoli in cui ogni persona ha una idea differente.
Ciao


 mantenere il codice piu` pulito (IMO).
PHP si è avvicinato molto alla programmazione oggetto, IMHO dovrebbero
farlo anche i programmatori. Questione di abitudine.
Ciao,
    Fabrizio
=== 
http://www.negusweb.it
 ===

 opportuna un'istruzione del tipo: Utente->save.
Perchè mai sarebbe piu' OO?
La responsabilità di un Utente sono le funzioni relative all'utente, non  
la sua memorizzazione.
Utente->getName (); //Francesca Malacchi
Utente->getPrefix (); //Dott.sa
Utente->getFullName (); //Dott.sa Francesca Malacchi
Mentre la memorizzazione o la gestione è un caso totalmente differente.
$SessionHandler->save ($Utente);
$Disk->save ($Utente);
$Database->save ($Utente);
$SendToFriend->send ($Utente);
Secondo me l'approccio Active Record si usa per granularità (considerata)  
inutile, non certo perchè è piu' OO rispetto a soluzioni differenti.


 farlo anche i programmatori. Questione di abitudine.
Sono d'accordo sulla questione di abitudine. Ed e` proprio questo che
intendevo qualche settimana (mese?) fa quando, parlando delle
innovazioni di PHP5 mi lamentavo che si stava avvicinando troppo a Java
e troppo poco a Python. :)
A me Java non piace, troppo rigido ;)
Bye.
-- 
Alessandro Pellizzari

 farlo anche i programmatori. Questione di abitudine.
Sono fondamentalmente daccordo, ma resta pur sempre un linguaggio di  
scripting.
E Property get/set esistono anche, ad esempio, in dot net.
Tendo ad evitarle principalmente perchè hanno qualche limite (non capisco  
bene come funzionino con i reference, ma gli ultimi esperimenti in  
proposito li ho fatti con php 5 beta.


 A me Java non piace, troppo rigido ;)
Non parlerei di rigidità, ma precisione. :-)
Ciao,
    Fabrizio

 proposito li ho fatti con php 5 beta.
Cioè? Di che limiti parli?
Ciao,
        Fabrizio

 
Scusa se taglio, sto cercando di farmi un quadro preciso.
Ora un dubbio.
Seguendo il tuo ragionamento, io dovrei mettere anche il load dentro
l'oggetto, cosi`:
class Utente
{
	function load($id) { $dao->load($id); }
}
Ma il $dao->load mi torna un oggetto Utente come risultato. Come
"scambio" l'oggetto che chiama il load del dao con quello tornato dal
dao?
Dovrei fare qualcosa tipo
$utente = new Utente();
$utente = $utente->load($id);
Invece di un semplice
$utente = new Utente();
$utente->load($id);
Entrambi i metodi, IMO, portano confusione. Il primo perche` non si
capisce che l'oggetto viene sovrascritto (e non so nemmeno se funzioni).
Il secondo perche` non si capisce dove vadano a finire i dati caricati.
Col "mio sistema" farei qualcosa tipo
$dao = DBManager->get("Utente");
$utente = $dao->load($id)
Dal quale si capisce (o almeno io capisco :) che $dao e` un'astrazione
della base dati (che sia DB o XML), mentre utente e` un singolo oggetto
di quella base dati.
Per il resto sono d'accordo con te sulla flessibilita`, ma era proprio
per questo motivo che avevo spostato la logica di load/save nel DAO e
non nell'oggetto.
Bye.
-- 
Alessandro Pellizzari


Parto dal presupposto che bisogna tenere le classi il più possibile
slegate tra di loro per consentire il massimo livello di scalabilità
del codice (ovvero l'aggiornabilità della classe che incide il meno
possibile sulle altre). Ma certe volte il legame è così stretto che
sono imprescindibili, come nel caso del salvataggio, IMHO.
Ciao,
     Fabrizio

 non nell'oggetto.
Il fatto di spostare la logica load/save è più che giusta, ma
lasciarsi anche il maggior margine di crescita del software è
auspicabile. :-)
Ciao,
         Fabrizio

 saprà a colpo d'occhio quali get è possibile fare e quali no.
Secondo il punto è un altro, non è tanto cosa è giusto fare e cosa è giusto 
non fare l'esperienza insegna si è vero ma ...
secondo me state prendendo delle decisioni per il futuro state pensando di 
scrivere del codice che funzioni sempre ed in tutte le esigenze
E' come fare una macchina che va a benzina a gasolio a metano etc. è 
impraticabile come strada.
Perchè tu puoi preventire 1,2,3,4,5,6,7,8,9,10
soluzioni per rendere il tuo codice più scalabile più manuntenibile più 
robusto più sicuro etc. Poi viene un programmatore più esperto di te e trova
11,12,13 (soluzioni) siamo punto ed a capo.
Bisogna nel limite del possibile rispettare si le buone regole di 
programmazione ma come in tutte le cose ci vuole il buon senso! bisogna fare 
quello che serve
al momento! non quello che serve per li futuro! questo non significa scivere 
codice corretto o non usare interfacce ma significa rendere le cose il più 
semplice possibile
qualcuno ora non ricordo chi,  ha scritto:
faccio:
....
function save()
{
         $dao->save($this);
         $xml->save($this);
}
----
Ed io ti dico se voglio poter salvare separatamente e come mi pare ? E se 
voglio salvare e spedire una mail ? E se.... come vedete "se" ne metto 
quante me ne vengono in mente
Io sono dell'idea che se avrei un tool per scrivere il codice e questo tool 
mi permettesse di scrivere quello che penso al diavolo buona programmazione! 
il fine ultimo oltre alle
caratteristiche che ho scritto sopra è scrivere meno codice possibile, per 
il futuro! pensateci sta tutto li!
Quindi perchè non scriverne il meno possibile subito ?
vantaggi ?
1) lo modifico più infretta più è semplice meno legami meno grattacapi
2) se qualcuno lo legge lo capisce al volo
3) codice più chiaro == con meno bug , codice con meno bug == codice più 
robusto
etc. etc.
ciao

 vantaggi ?
Perchè è meno scalabile. Potrei anche non usare le classi ed utilizza
il linguaggio in forma procedurale (che implica meno sforzo
progettuale), ma mi troverei di fronte ad un'accozzaglia di codice (non
sempre, ovviamente) difficilmente gestibile. 
Ciao,
    Fabrizio

Cioč?
nel senso che se un tool "inteligente" lo faceva per conto mio tutti questi 
problemi o se se se non me li ponevo.
Quindi il fine ultimo č che lo faccio per scrivere meno codice ... -)
ciao

 sono imprescindibili, come nel caso del salvataggio, IMHO.
In realtà è spesso molto piu' comodo fare come dici tu. Ma livello  
teorico, secondo me, è comunque scorretto.
In una classe di così basso livello preferirei un'altro approccio.


 semplice possibile
Approccio detto anche YAGNI (maggiori cenni su google).
Ottimo approccio imho.


 Cioè? Di che limiti parli?
Non ho ben capito come si faccia (ma ci ho studiato poco, ripeto) a fare  
in modo che __get restituisca un reference in un caso e nell'altro  
restituisca una nuova istanza della variabile (ovviamente presupponendo di  
dover restituire array e primitive non oggetti - per i quali il discorso è  
differente).
Ma ripeto, ci ho studiato molto poco.


 applicativi differenti.
Beh, ragazzi, mi pare di capire che gli oggetti sono come le scarpe:
ognuno ha le sue, e solo per puro caso alcune coincidono. :)
E` stato molto istruttivo seguire la discussione, e spero che
continuiate. Io credo di saperne troppo poco per dare informazioni
aggiuntive, ma sto seguendo con molto interesse i vari punti di vista.
Grazie.
-- 
Alessandro Pellizzari


Quello anche per me č sempre bello parlare di queste cose

 si parte da quelli (information hiding etc.)
Quello di cui parlavo io è One Responsibility.
