Bueno, en lugar de pegaros un rollo patatero sobre mis divagaciones mentales sobre programación os pondré un ejemplo de cómo lo he hecho yo en un caso concreto.
Veamos, yo necesitaba representar empresas que eran clientes de la mia. La base de datos ya estaba diseñada (en Oracle) y tenía que respetar su estructura.
Evidentemente diseñé mi clase TEmpresa con todas sus propiedades y métodos. Esta clase (como todas las demas) no tiene acceso a la BD, si no que "ve" a un módulo de datos (DmFacturas) que es quien se encarga tanto de servirle los datos como de manipularlos.
Por otro lado cree una clase TListaEmpresas que era la que se encargaba de mostrar los conjuntos de empresas, por ejemplo en una pantalla de búsqueda. Esta clase tiene distintos métodos que son los que se encargan de efectuar las búsquedas:
CargaPorCodigo(Codigo: String), CargaPorNombre(Nombre: String)...
La clase TlistaEmpresas lanza una función en DmEmpresas que devuelve un TList con estructuras con los datos de las empresas. En estas estructuras solo se guardan los datos "propios" de la empresa, no aquellos vinculados (como podrían ser sus centros de trabajo o el nombre de sus empleados). Con cada item de la TLista iremos creando una TEmpresa i la guardaremos en una TObjectlist interna de TListaEmpresas (esta es la lista propiamente dicha).
Para cargar los datos en el grid de búsqueda tansolo tendremos que ir pidiendo los datos de cada posición de TListaEmpresa en un bucle. Además, podemos ir guardando en la propiedad Objects del Grid cada una de las TEmpresa que esté vinculada al registro, así, si el control permite ordenaciones (o si en lugar de un grid es un combo) no perderemos el vinculo al objeto.
Cuando el usuario eliga la empresa que quiere, la pantalla retorna el propio objeto de manera que la pantalla que llamó a la de de búsqueda tenga acceso a él y pueda mostrar el resto de datos o editarlos o lo que haga falta.
Para acabar solo remarcar dos aspectos que considero cruciales en este tipo de arquitecturas para evitar un desperdicio desmesurado de memoria.
En primer lugar, los objetos "grandes" que contienen apuntadores o incluso listas a otros objetos no tienen que instancirlos ni cargarlos en su constructor ya que muchas veces ni se consultarán sus datos ni se modificarán y estaremos cargando mucho la memoria y efectuando consultas a la BD innecesarias. Creo que lo mejor es instanciarlos en el metodo de lectura y destruirlos en el destructor. Por ejemplo, en el caso TEmpresa, supongamos que tenemos una propiedad Centros de tipo TListaCentros que apunta a una lista de TCentro's:
Código:
private
FCentros: TListaCentros;
...
public
property Centros: TListaCentros read GetCentros;
.....
constructor TEmpresa.Create(AOwner: TComponent);
begin
inherited;
...
FCentros := Nil;
end;
destructor Destroy;
begin
...
FCentros.Free;
inherited;
end;
function GetCentros: TListaCentros;
begin
if not Assigned(FListaCentros) then
begin
FlistaCentros := TListaCentros.Create(Self);
FlistaCentros.Carga(//parametros de carga);
end;
Result := FlistaCentros;
end;
La otra cosa que considero indispensable es asegurarnos que, por ejemplo, por cada instancia de TEmpresa NO se cree una de TDmEmpresa ya que al cargar, por ejemplo, una lista 100 de empresas, ''crearemos 100 modulos de datos!!!
Bueno, me acabo de leer todo lo que escrito y creo que no se entiende nada, pero es que es que sobre este tema se escriben libros enteros. Por otra parte para explicar mejor el funcionamiento del ejemplo os tendría que pegar aquí todo el programa, y tampoco seria plan!