Newsgroup: it.comp.lang.delphi
Titolo: Secondo create

Ho una classe TBudgets il cui constructor inizializza i campi dell'oggetto 
con dei valori di default. A volte sarebbe invece opportuno usare i valori 
provenienti da un record di un dataset. Ecco le mie domande:
- posso creare un secondo constructor diverso dal primo ?
- l'accesso al dataset con una chiave per consentire la raccolta dei dati 
del record con cui inizializzare il mio oggetto č meglio farla come un 
metodo dell'oggetto, oppure indipendentemente (salvo fornire all'oggetto i 
dati raccolti) ?
- quale č il modo migliore per passare all'oggetto i campi del record ? 
 

 - quale ï¿½ il modo migliore per passare all'oggetto i campi del record ?
 
Crea un costruttore che accetti come parametri i valori da estrarre dal record, passando tali valori quando crei l'istanza estraendoli dal record in questione.
 
Ciao,
  Marco.
 
-- 
MARCO BREVEGLIERI
#Home: 
http://www.marco.breveglieri.name
 
#Blog: 
http://www.compilaquindiva.net
 

 - quale ï¿½ il modo migliore per passare all'oggetto i campi del record ?
 
Crea un costruttore che accetti come parametri i valori da estrarre dal 
record, passando tali valori quando crei l'istanza estraendoli dal record in 
questione.
 
Ciao,
  Marco.
Grazie del consiglio. Nel frattempo avevo provato ma fare un metodo che, 
avendo come parametro il dataset e la chiave a cui accedere, riempiva i 
campi dell'oggetto estraendoli dal record.
Mi pare però che mi suggerisci di fare all'esterno l'accesso al dataset, 
cosa che sarei propenso a fare perchè me lo consigli tu, ma non percepisco 
il problema. Puoi provare a spiegarmelo ? Ciao 
 

 il problema. Puoi provare a spiegarmelo ? Ciao
 
Non c'è un "problema" specifico, ma facendo così la tua classe rimane indipendente da componenti per l'accesso ai dati, svolge un solo compito, può essere modificata più facilmente, può essere impiegata in Unit Test senza doversi tirare dietro altre dipendenze e così via.
 
In breve, rispetta il pattern SRP (Single Responsibility Principle):
http://en.wikipedia.org/wiki/Single_responsibility_principle
 


Allora, definito così il create che all'esterno accede alla chiave 
ineteressata del dataset e passa i dati come parametri del create, adesso 
vorrei avere la possibilità di creare l'oggetto con valori tutti a zero, 
Quindi mi basterebbe semplicemente ereditare il create della classe base 
(TObject) senza alcun parametro e introdurre solo le semplici istruzioni 
dell'azzeramento. Un secondo create implica un altro nome (d'altronde uno 
stesso nome è impossibile..) ? C'è qualche consuetudine al riguardo ? 
 

 stesso nome ï¿½ impossibile..) ? C'ï¿½ qualche consuetudine al riguardo ?
 
Posta del codice perché altrimenti non è possibile fare riferimenti chiari e sicuri a quello che intendi, né dare esempi certi.


Prima versione della classe TMensiliBud:
-----------------------------------------
Unit StoricoMensiliU;
{ Classe TMensiliBud che rappresenta i valori (in formato stringa)
  dei budget mensili di una Categoria per un determinato anno
  I valori vengono assunti dal record Budget con chiave Anno+Cat }
interface
uses
 Windows, SysUtils, Classes, Graphics, Controls,
  StdCtrls, DBCtrls, Db, DBTables, Dialogs;
type
  TMensiliBud = class
  private
    FAnno: string;
    FCat: string;
    FMensiliB: TStringList;
    function SetMensiliB(aTable: TTable; aAnno, aCat: string; FMensiliB: 
TStringList): boolean;
  public
    property MensiliB: TStringList read FMensiliB;
    constructor Create(aTable: TTable; aAnno, aCat: string);
    destructor Destroy; override;
    function GetMensiliB: TStringList;
end;
 
implementation
 
constructor TMensiliBud.Create(aTable: TTable; aAnno, aCat: string);
var i: integer;
begin
   FMensiliB:= TStringList.Create;
   // Accedi a aTable con chiave aAnno+aCat e raccogli i dati dei campi
   if SetMensiliB(aTable, aAnno, aCat, FMensiliB) then
   begin
      FAnno:= aAnno;
      FCat := aCat;
   end else
   begin
      FAnno:= '9999';
      FCat := aCat+chr(13)+' non trovata';
      for i:= 0 to 12 do
         FMensiliB.Add('0');
   end;
end;
 
destructor TMensiliBud.Destroy;
begin
   FMensiliB.Free;
   Inherited Destroy;
end;
 
function TMensiliBud.GetMensiliB: TStringList;
begin
   result:= FMensiliB;
end;
 
In questo caso la classe la istanziavo cosě:
 MensiliBud:= TMensiliBud.Create(BudgetTable, '2012','xxx');
 
Seconda versione (TMensiliB):
-------------------------------------------------------
unit MensiliBU;
interface
uses
 Windows, SysUtils, Classes, Graphics, Controls,
  StdCtrls, DBCtrls, Db, DBTables, Dialogs;
type
  TMensiliB = class
  private
    FAnno: string;
    FCat: string;
    FMensiliB: TStringList;
  public
    property MensiliB: TStringList read FMensiliB;
    constructor Create; virtual;
    destructor Destroy; override;
    procedure FillRecFromDB(aAnno,aCat: string; 
a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12: integer);
    function  GetMensiliB: TStringList;
end;
 
implementation
 
constructor TMensiliB.Create;
var i: integer;
begin
   FMensiliB:= TStringList.Create;
   inherited Create;
   for i:= 0 to FMensiliB.Count-1 do
     FMensiliB[i]:= 0;
end;
 
destructor TMensiliB.Destroy;
begin
   FMensiliB.Free;
   Inherited Destroy;
end;
 
function TMensiliB.GetMensiliB: TStringList;
begin
   result:= FMensiliB;
end;
 
procedure TMensiliB.FillRecFromDB(aAnno,aCat: string; 
a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12: integer);
var tot: integer;
begin
   tot:= 0;
   tot:= a01;
   tot:= tot + a02;
   tot:= tot + a03;
   tot:= tot + a04;
   tot:= tot + a05;
   tot:= tot + a06;
   tot:= tot + a07;
   tot:= tot + a08;
   tot:= tot + a09;
   tot:= tot + a10;
   tot:= tot + a11;
   tot:= tot + a12;
   FMensiliB.Add(aAnno);
   FMensiliB.Add(aCat);
   FMensiliB.Add(inttostr(a01));
   FMensiliB.Add(inttostr(a02)-a01);
   FMensiliB.Add(inttostr(a03));
   FMensiliB.Add(inttostr(a04));
   FMensiliB.Add(inttostr(a05));
   FMensiliB.Add(inttostr(a06));
   FMensiliB.Add(inttostr(a07));
   FMensiliB.Add(inttostr(a08));
   FMensiliB.Add(inttostr(a09));
   FMensiliB.Add(inttostr(a10));
   FMensiliB.Add(inttostr(a11));
   FMensiliB.Add(inttostr(a12));
   FMensiliB.Add(inttostr(tot));
end;
 
end.
In questo secondo caso invece la classe la istanzio cosě:
 MensiliB:= TMensiliB.Create;
 MensiliB.FillRecFromDB( BudgetTable.FieldByName('ANNO').AsString,
                                 BudgetTable.FieldByName('ID').AsString,
                                 BudgetTable.FieldByName('SAL_Y01').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y02').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y03').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y04').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y05').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y06').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y07').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y08').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y09').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y10').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y11').AsInteger,
                                 BudgetTable.FieldByName('SAL_Y12').AsInteger 
 );
---------------------------------------------
Vorrei capire come fare per creare l'oggetto con due create diversi. Supponi 
che io voglia, in alcuni casi, ottenere i valori dei campi di cui sopra da 
un array o una StringList esterna, dovrei definire un constructor Create2 ? 
 

 un array o una StringList esterna, dovrei definire un constructor Create2 ?
 
Ma alla fine non hai fatto come ho detto io.
 
Io avevo scritto questo:
"Meglio estrarre i dati dal record all'esterno della classe, altrimenti attribuisci a questa troppe responsabilità"
 
Tu hai fatto un costruttore che accetta come parametro una TTable, quindi sei andato in senso contrario. :)
 
La tua ultima domanda aveva risposta automatica se tu avessi implementato un costruttore che prendesse direttamente i parametri del tipo appropriato; ad esempio:
 
  constructor TMensiliB.Create(aAnno,aCat: string;
    a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12: integer);
 
Poi non trovo indispensabile valorizzare tutti questi dati nel costruttore: sarebbe sufficiente inizializzare quelli fondamentali (ad esempio, "anno" e "cat") e per i restanti valorizzare le proprietà individualmente.


Ma alla fine non hai fatto come ho detto io.
 
Io avevo scritto questo:
"Meglio estrarre i dati dal record all'esterno della classe, altrimenti 
attribuisci a questa troppe responsabilità"
 
Tu hai fatto un costruttore che accetta come parametro una TTable, quindi 
sei andato in senso contrario. :)
 
La tua ultima domanda aveva risposta automatica se tu avessi implementato un 
costruttore che prendesse direttamente i parametri del tipo appropriato; ad 
esempio:
 
  constructor TMensiliB.Create(aAnno,aCat: string;
    a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12: integer);
 
Poi non trovo indispensabile valorizzare tutti questi dati nel costruttore: 
sarebbe sufficiente inizializzare quelli fondamentali (ad esempio, "anno" e 
"cat") e per i restanti valorizzare le proprietà individualmente.
 
Ciao,
  Marco.
Si che ho fatto come hai detto. Il codice di TMensiliBud è quello che avevo 
scritto prima. Il codice di TMensiliB è quello che ho riscritto, dove la 
sequenza di utilizzo è: 1-accesso con chiave al dataset; 2-creazione 
dell'oggetto vuoto; 3-riempimeno dei campi con quelli del record. Però 
potevo valorizzare i dati nel costruttore, come suggerisci tu sopra. Ma ho 
già un create nella classe. Questo secondo lo dovrò chiamare con un altro 
nome, o no ?
PS: la partita non mi è piaciuta ... 
 

Questa classe e' SBAGLIATA.
Se il dataset non è fatto ESATTAMENTE come quello che usi adesso, va tutto ai festini del nano di arcore.
Cero, puoi aggiungere un altro costruttore che usa un tdataset che espone campi diversi..e poi un altro, ed un altro ancora.
Alla fine avrai una classe con 5 righe e 90 costruttori.
 
Come ti ha suggerito Marco, la via giusta e' avere un costruttore che accetta come parametri i valori che ti servono.
 
A.