Ver Mensaje Individual
  #3  
Antiguo 10-10-2012
Avatar de gatosoft
[gatosoft] gatosoft is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Bogotá, Colombia
Posts: 833
Reputación: 22
gatosoft Va camino a la fama
Bueno, además de la lectura obligada que recomienda Delphius, es necesario poner en práctica los conceptos aprendidos, que pueden llegar a ser muy abstractos cuando ya se tiene un paradigma de programación en la cabeza...

Cita:
Empezado por agustinbus Ver Mensaje
1- Es conveniente crear un Unit para cada clase, es decir crear un Unit para TClientes uno para TProveedores, etc.. y referenciarlos segun mi necesidad? o uno solo con todas las clases?
Creo que tu mismo te repondes: "Es conveniente...según mi necesidad" (al igual que reponde Delphius "Depende de tus necesidades")

En mi poca experiencia personal sobre el tema, DEFINITIVAMENTE SI te recomiendo trabajar una unidad por cada clase, aunque lógicamente habrán ocasiones en que sea necesario definir mas de una clase en la misma unidad. (Generalmente cuando estan muy relacionadas).

A manera de ejercicio recomiendo siempre pensar que cada clase se diseña para ser publicada y comercializada de forma separada, como si estuvieras diseñando un componente. El objetivo de esto es llegar a un nivel alto de abstracción e independencia de cada clase.

Hago un paréntesis para comentar un detalle en la forma como nombras las clases, aunque no es importante, (y además depende de tus necesidades), tus clase no deberían llamarse TClientes, TProveedores, TFacturas... sino TCliente, TProveedor, TFactura... sencillamente por que eso te lleva a un nivel mas de abstracción. (individual vs. colectivo). No es lo mismo decir LosClientes.Crear, LosClientes.Guardar, que ElCliente.Cargar y ElCliente.Guardar. La lógica y el procesamiento en cada caso es distinto. Aunque vuelvo y repito depdne de lo que estes trabajando.

Cita:
Empezado por agustinbus Ver Mensaje
2- Para un alta por ejemplo de un cliente, quien seria el responsable de hacer el insert en la BBDD? La capa de datos? la de Negocio? El Unit TCliente con un metodo propio de la clase?
Necesariamente la capa de datos... en el momento que comiences a definir sentencias SQL en la capa de negocio estas reduciendo el modelo a dos capas... En general cada capa debe ser lo mas sencilla posible, al punto que las primeras capas sean como lenguaje natural... (Cliente.Guardar y la capa de Datos o de persistencia sabrá como se las arregla para almacenar dicha información.

Esto es importante ya que si logras independizar la capa de datos de las otras dos, podras pensar en un sistema multiBD o en un sistema que trabaje igual Local que de forma remota.

Cita:
Empezado por agustinbus Ver Mensaje
3- Cual es el rol de la capa de Negocio?
La capa de negocio se debe concentrar en recoger los datos (De la GUI, De un archivo, de la capa de persistencia), procesarlos, validarlos (de acuerdo a unas reglas de negocio) y enviarlos de nuevo a la Capa de presentación o a la de persisntecia según corresponda.

Piensa que el dia de mañana ya no vas a trabajar tu sistema en un PC con interfaz Windows, sino que vas a exponer tu aplicación como servicios web... Tu lógica de negocio o deberia cambiar, ni tampoco tu capa de persistencia...

estaria mal encontrar en tu capa de negocio algo como:
Código Delphi [-]
Procedure SetNombreCliente;
Begin
  Nombre:= Form1.Edit1.text;
end;

Por que estarias amarrando tu clase a la forma que estas trabajando.... Además como regla, "las capas internas no deben utilizar (Uses) las capas externas"...

Presentación ==Utiliza==> Negocio ==Utiliza==> Persistencia

Cita:
Empezado por agustinbus Ver Mensaje
Tenia pensada otra forma de trabajar pero no se si esta bien, esta forma seria:

- Crear Units para cada clase por ejemplo TCliente
- Cada clase tendra sus datos privados (nombre, apellido, fecha nacimiento,etc...)
- Cada clase tendra sus propios metodos get y set para acceder a los datos privados.
No hay discusión, es regla por la filosofía de objetos

Cita:
Empezado por agustinbus Ver Mensaje
- Cada clase tendra sus propios metodos para mantener la base de datos(es decir altas bajas modificaciones). Me refiero a crear un metodo insertar que guardara los datos en la base de datos por lo tanto cuando quiera guardar los datos del cliente hare:
Código Delphi [-]
cliente.Insertar(nombre,apellido,...);

y la definicion del metodo seria mas o menos asi:
Código Delphi [-]
cliente.Insertar(nombre,apellido,...);
begin
  QClientes.Close;
  QClientes.SQL.Clear; 
  QClientes.SQL.Add('INSERT INTO Clientes (NOMBRE, APELLIDO,...) values (:nom, :ape...)');
  QClientes.ParamByName('nom').Value := nombre;
  QClientes.ParamByName('ape').Value := apellido;
  QClientes.ExecSQL;
end;

Es correcto el razonamiento anterior? Un problema que encuentro es al momento de reutilizar la clase TCliente tendre que utilizar el mismo nombre para el TZQuery es decir QClientes.
Aquí en cambio si discuto.... como te comentaba anteriormente, es recoemndable (No es verdad absoluta) mantener alejado de la capa de negocio los componentes especificos de base de datos, o algo que amarre a la clase a un motor exclusivo...

Por otro lado, te sugeriria que manejaras otra filosofia en cuanto a la forma como ves la clase clientes... Clientes.Insertar(parametros)... está muy ligado a pensar en base de datos.... debes pensar mas en tu negocio y en lo que representa para ti un cliente... Es decir, deberias trabajar algo como:

Código Delphi [-]
cliente.Nuevo; //inicializa las variables
cliente.Nombre:= 'Perico';
Cliente.Apellido:= 'De los Palotes';
Cliente.Validar;


if Cliente.EstaOK then
   cliente.Guardar
else
   cliente.GenerarError('Error'); //Lo alamcena para ser presentado en la GUI según convenga...
                                  // o simplemente geners el raise... 


Cliente.Cargar(CodigoDeCliente);
Cliente.CalcularSaldos;


Separar en capas y trabajar clases independientes (tipo componente) puede representar un trabajo dispendioso... para algunos innecesario o redundante, pero tiene muchas ventajas a la hora de moverte entre arquitecturas..

En mi experiencia reciente, tuve la oportunidad de comprobar sus beneficios....

Yo tenia una aplciación Cliente servidor que utilizaba una clase TComprobanteContable. esta clase a su vez utilizaba una clase TEjecutorSQL que se encargaba de hacer el "trabajo sucio" en la base de datos... entonces mi clase funcionaba algo asi:

Código Delphi [-]
Function TComprobanteContable.Guardar: Boolean;
Begin
  if Self.ValidarDatos then
     if EjecutorSQL.Ejecutar('GuardarComprobantes', '<%ListaParametros%>') then
        Result:= True
     else
        Result:= False;  
end;

Mi ejecutorSQL es un componente que previamente he conectado a una base de datos (PostgreSQL, Interbase, Oracle o SQL server)... ¿como lo hace? pues a mi clase TComprobanteContable no le importa... solo le importa que cumpla con su parte...

Bueno, siguiendo con la historia... cuando quise migrar a la nube mi aplicación con DataSnap, pues no tuve que cambiar mi GUI, ni mi TComprobanteContable, ni mi ejecutor... solo tuve que crear unas clases TComprobanteContableRemoto, TEjecutorSQLRemoto que utilizaban los Mismos Metodos de las clases definidas inicialmente, es decir algo como:

Código Delphi [-]
Function TComprobanteContableRemoto.Guardar: Boolean;
Begin
  Result:= ClientModule1.ServerMethodsComprobanteClient.Guardar;
end;



Espero haber sido claro y haberte ayudado en algo...
Responder Con Cita