Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Programación Orientada a Objetos - Aplicación (https://www.clubdelphi.com/foros/showthread.php?t=85231)

pape19 18-02-2014 22:01:40

Programación Orientada a Objetos - Aplicación
 
Buenas tardes.

A algunos mi consulta les parecerá algo tonta, pero es algo que me está costando implementar en Delphi y necesito de su ayuda.

Las aplicaciones que he hecho en Delphi, sean simples o con alguna complejidad fue siempre programando de manera procedural, nunca cree una clase; y ahora necesito y siento curiosidad por aplicar todos mis conocimientos teóricos aprendidos de POO en la práctica, y tengo ciertas dudas del orden en el que se escriben las cosas.

Vamos a suponer, que mi aplicación es un ABM de Empleados, con una base de datos Firebird. Para conexion con la bd utilizo componentes IB. Creo la siguiente clase:

Código Delphi [-]
TEmpleado = class
    Referencia: Integer;
    Nombre: String;
    FechaNacimiento: TDate;
    Procedure ValidarEmpleado(objEmpleado : TEmpleado);
    Procedure GuardarEmpleado(objEmpleado : TEmpleado);

  private
    { Private declarations }
  public
    { Public declarations }
    Procedure SetReferencia(IdEmpleado: Integer);
    Procedure SetNombre(Nombre: String);
    Procedure SetFechaNacimiento(FechaNacimiento: TDate);
    Function GetReferencia(): Integer;
    Function GetNombre(): String;
    Function GetFechaNacimiento(): TDate;

Luego tengo un form(F_Empleados) con tres botones(alta, baja y modificación de empleados) y un DataModule(Name dmDatos) con un objeto IBTable, llamado tblEmpleados. El boton Alta:

Código Delphi [-]
procedure TF_Empleados.btnAltaClick(Sender: TObject);
begin
    Empleado := TEmpleado.Create();
    TblEmpleados.Active := True;
    TblEmpleados.Insert;
    F_ABMEmpleado.show;
end;

F_ABMEmpleado es otro form, el cual muestro al apretar Alta, donde tengo 3 Edits para el ingreso de los datos del empleado. Y un botón Guardar.

En ese botón guardar hago...

Código Delphi [-]
    Empleado.SetReferencia(Edit1.Text);
    Empleado.SetNombre(Edit2.Text);
    Empleado.SetFechaNacimiento(Edit3.Text);
    Empleado.ValidarEmpleado(Empleado);
    Empleado.GuardarEmpleado(Empleado);
    F_ABMEmpleado.Close;

Ahora les muestro mis métodos ValidarEmpleado() y GuardarEmpleado() de la clase Empleado

Código Delphi [-]
Procedure TEmpleado.ValidarEmpleado(objEmpleado : TEmpleado);
Begin
  if ((objEMpleado.Nombre = '') then
  Begin
    showmessage('ERROR');
    abort;
  End;
End;

Procedure TEmpleado.GuardarEmpleado(objEmpleado : TEmpleado);
Begin
    dmDatos.tblEmpleadosREFERENCIA.Value := objEmpleado.Referencia;
    dmDatos.tblEmpleadosNOMBRE.Value := objEmpleado.Nombre;
    dmDatos.tblEmpleadosFECHA_NAC.Value := objEmpleado.FechaNacimiento;

    dmDatos.tblEmpleados.Post; //IBTable
    dmDatos.transFleetDB.Commit; //IBTransaction
    dmDatos.tblEmpleados.Active := False;
End;

El código funciona. Ahora bien...es la manera correcta de hacerlo????? En el método GuardarEmpleado de la clase Empleado, defino tblEmpleados.... para pasar los datos a la base, por lo cual, esta clase no sirve para otra aplicación donde se necesite una clase Empleado; esto ultimo es lo que me hace dudar de si está bien escrito o no. Que consejos pueden darme??


Disculpen las "pifias" que pude haber tenido en la explicación. Muchas gracias.

ecfisa 19-02-2014 00:41:36

Hola pape19.

Decir la manera "correcta" de hacerlo sería como decir que tu código es incorrecto y no es así, por que como mencionas, funciona bién. Pero creo que se le podrían hacer algunas mejoras.

Si bién está probado, el código siguiente es sólo un ejemplo de guía.
Código Delphi [-]
unit uEmpleado;

interface

uses
  Windows, Messages, SysUtils, Controls;

type
  TDataSetAction = (daEdit, daInsert, daAppend);

type
  TEmpleado = class(TObject)
  private
    FNombre: string;
    FNacimiento: TDate;
    FReferencia: Integer;
    procedure SetNacimiento(const Value: TDate);
    procedure SetNombre(const Value: string);
    procedure SetReferencia(const Value: Integer);
    procedure SetAction(const Value: TDataSetAction);
  public
    constructor Create;
    procedure Save;
    procedure Delete;
    property Action: TDataSetAction write SetAction;
    property Nombre: string read FNombre write SetNombre;
    property Nacimiento: TDate read FNacimiento write SetNacimiento;
    property Referencia: Integer read FReferencia write SetReferencia;
    destructor Destroy; override;
  end;

implementation

uses Unit3; // DataModule

constructor TEmpleado.Create;
begin
  inherited;
  with DataModule1 do
  begin
    if not IBTransaction1.InTransaction then
      IBTransaction1.StartTransaction;
    IBDataSet1.Open;
  end;
end;

procedure TEmpleado.SetAction(const Value: TDataSetAction);
begin
   with DataModule1.IBDataSet1 do
    case Value of
      daEdit: Edit;
      daInsert: Insert;
      daAppend: Append;
    end;
end;

procedure TEmpleado.SetNombre(const Value: string);
begin
  if Value <> FNombre then
    FNombre := Value;
end;

procedure TEmpleado.SetNacimiento(const Value: TDate);
begin
  if Value <> FNacimiento then
    FNacimiento := Value;
end;

procedure TEmpleado.SetReferencia(const Value: Integer);
begin
  if Value <> FReferencia then
    FReferencia := Value;
end;

procedure TEmpleado.Save;
begin
  if Nombre = EmptyStr then
    raise Exception.Create('Error: Nombre es un dato requerido');
  // aquí pueden ir otras comprobaciones...
  with DataModule1 do
  begin
    IBDataSet1.FieldByName('REFERENCIA').AsInteger := Referencia;
    IBDataSet1.FieldByName('NOMBRE').AsString   := Nombre;
    IBDataSet1.FieldByName('FECHA_NAC').AsDateTime := Nacimiento;
    IBDataSet1.Post;
  end;
end;

procedure TEmpleado.Delete;
begin
  if MessageBox(0,'¿ Desea eliminar el registro ?',
                '',MB_ICONQUESTION+MB_YESNO)= IDYES then
    DataModule1.IBDataSet1.Delete;
end;

destructor TEmpleado.Destroy;
begin
  with DataModule1 do
  begin
    IBDataSet1.Close;
    IBTransaction1.Commit;
  end;
  inherited;
end;

end.

Un ejemplo de uso:
Código Delphi [-]
...
implementation

uses uEmpleado;


var
  Empleado: TEmpleado;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Empleado:= TEmpleado.Create;
end;

// Edit
procedure TForm1.btnEditClick(Sender: TObject);
begin
  with Empleado do
  begin
    Action:= daEdit;
    Referencia:= IntToStr(EditRef.Text);
    Nombre:= EditNomb.Text;
    Nacimiento:= DateToStr(EditNac.Text);
    Save;
  end;
end;

// Insert (para Append es igual, solo cambia: Action:= daAppend)
procedure TForm1.btnInsertClick(Sender: TObject);
begin
  with Empleado do
  begin
    Action:= daInsert;
    Referencia:=  IntToStr(EditRef.Text);
    Nombre:= EditNomb.Text;
    Nacimiento:= DateToStr(EditNac.Text);
    Save;
  end;
end;

// Delete
procedure TForm1.btnDeleteClick(Sender: TObject);
begin
  Empleado.Delete;
end;

...

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Empleado.Free;
end;

Saludos :)

nlsgarcia 19-02-2014 01:33:50

Daniel,

:) ^\||/

Nelson.

Neftali [Germán.Estévez] 19-02-2014 09:19:37

Yo creo que la idea es buena. Se pueden modificar algunas cosas, pero el camino es el correcto.
Algunas sugerencias...

(1) En la parte public de tu empleado has definido procedures para rellenar los diferentes "campos". Utiliza propiedades. Si además las colocas en la parte published te permitirá utilizar RTTI para trabajar con ellas. Lo cual te da mucha potencia y es muy útil para trabajar con POO, aunque tal vez eso puedas dejarlo para más adelante. Tal como te ha indicado ecfisa.

(2) Si deseas aprovechar tu clase TCliente en otros lugares, deberías crear una propiedad (o las que necesites) para asignar los componentes de Base de Datos (TDatabase, TDataSet,...). De esa forma si la utilizas en otra aplicación sólo deberás rellenar esas propiedades con los nuevos valores.
De esa forma "extraes" de la clase los elementos "concretos" que la unen a tu aplicación actual y la haces más universal.
Algo así como los parámetros de una función.

(3) Siguiendo con el punto anterior, si cada clase va a taner unas propiedades para la conexión a Base de Datos, lo lógico sería crear una clase "base" que posea los métodos, propiedades y código comunes a todas. De esta forma evitarás mucho código.

(4) Más adelante, si dominas la herencia y con un poco de RTTI, puedes hacer que métodos como el Save, Delete, Buscar,... de la diferentes clases puedan estar codificados casi por completo en la "clase base", de esa forma si tienes 10 clases no tienes que implementarlos en todas ellas.

Código Delphi [-]

  TBaseClass = class (TObject)
    ...    
  public
    property Connection:...
    Property Table:....
  end;

  TCliente = class(TBaseClass)
  private
    ...
  published
    ...
    procedure Save;
    procedure Delete;
    procedure Update;
    ...
  end;

pape19 21-02-2014 21:23:47

Sus respuestas me han orientado muchísimo, sobre todo para poder encontrar información adicional. Por ejemplo, no tenía muy en claro lo que era RTTI; si bien he visto que no es fácil de aplicar, con estudio todo se aprende, y además el esfuerzo vale la pena porque realmente simplifica mucho código y logra aplicaciones con clases más "parametrizables" por decirlo de alguna manera. Lo que lleva a más reutilización, el anhelo de cualquier programador que toma esto como actividad, creo yo.

Dejo un link con un manual que me ha servido mucho para iniciar este camino por la POO en Delphi.

http://delphi.about.com/od/oopindelp...elphi_oop2.htm

En el FTP he subido su traducción:

http://terawiki.clubdelphi.com/Delph...+en+Delphi.rar



Neftalí y ecfisa, muchas gracias! Saludos!

nlsgarcia 22-02-2014 05:37:57

pape19,

Cita:

Empezado por pape19
...siento curiosidad por aplicar todos mis conocimientos teóricos aprendidos de POO en la práctica...si bien he visto que no es fácil de aplicar, con estudio todo se aprende...

Revisa estos links:
Cita:

POO en Delphi : http://www.delphiaccess.com/forum/%2...-delphi%29-34/

Run-Time_Type_Information_In_Delphi : http://terawiki.clubdelphi.com/Delph..._In_Delphi.rar

Object Oriented Programming in Delphi: Object_Oriented_Programming_in_Delphi.rar
Espero sea útil :)

Nelson.


La franja horaria es GMT +2. Ahora son las 00:57:20.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi