Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Reusar unidad en Delphi (https://www.clubdelphi.com/foros/showthread.php?t=87676)

martin.lazzeri 10-02-2015 12:53:50

Reusar unidad en Delphi
 
Hola Gente!

Estoy desarrollando un proyecto para una materia, tenemos que usar diferentes estructuras de datos, como por ejemplo arboles, listas simples y doblemente enlazadas.

Por ejemplo aca les dejo la libreria de arbol:

Código Delphi [-]
unit Arbol;

interface

const
      posNula = -1;
      valorNulo = 0;
      claveNula = 'AAAAAA';
      ruta = 'C:\Users\Martin\Desktop\prog2\Veterinaria\Arbol\';

type

      TipoPosicion = integer;
      tipoclave = string[6];

      RegistroDatosArbol = record
                                  Clave : TipoClave;
                                  Padre : TipoPosicion;
                                  HijoDerecho : TipoPosicion;
                                  HijoIzquierdo : TipoPosicion;
                           end;

      TipoArchivoDatos = file of RegistroDatosArbol;

      RegistroControlArbol = record
                                    Raiz : TipoPosicion;
                                    Cantidad : integer;
                                    Borrado : TipoPosicion;
                             end;
      TipoArchivoControl = file of RegistroControlArbol;

      TipoArbol = record
                           D : TipoArchivoDatos;
                           C : TipoArchivoControl;
                  end;
var
      Me : TipoArbol;

// Operaciones de la libreria
Procedure CrearArbol(var Me : TipoArbol; archivoDatos : string; archivoControl : string );
Procedure AbrirArbol (var Me : TipoArbol);
Procedure CerrarArbol (var Me : TipoArbol);
Function Raiz(var Me : TipoArbol) : TipoPosicion;
Function Padre(var Me: TipoArbol; pos : TipoPosicion) : TipoPosicion;
Procedure CapturarNodo(var Me : TipoArbol; pos : TipoPosicion; var regDatos : RegistroDatosArbol);
Procedure ModificarNodo(var Me : TipoArbol; pos : TipoPosicion; regDatos : RegistroDatosArbol);
Procedure InsertarNodo(var Me: TipoArbol; pos : TipoPosicion; regDatos : RegistroDatosArbol);
Function Buscar(var Me: TipoArbol; clave: TipoClave; var pos: TipoPosicion) : boolean;

implementation

Procedure CrearArbol(var Me : TipoArbol; archivoDatos : string; archivoControl : string );
var
    registroControlAux : RegistroControlArbol;
begin
      {$I-}
      assign(Me.D, ruta + archivoDatos);
      assign(Me.C, ruta + archivoControl);

      // Abro el archivo de datos para solo lectura
      reset (Me.D);

      // Verifico que no haya errores
      if(IORESULT <> 0)
        then
            rewrite (Me.D); // Creo el archivo, ya que no existía y se abre para escritura

      //Abro el archivo de control para solo lectura
      reset (Me.C);

      //Verifico que no haya errores
      if(IORESULT <> 0)
        then
            begin
                  rewrite (Me.C); //Creo el archivo, ya que no existía y se abre para escritura

                  //A continuación inicializo los campos del registro
                  registroControlAux.Raiz := posNula;
                  registroControlAux.Cantidad := 0;
                  registroControlAux.Borrado := posNula;
                  write (Me.C, registroControlAux); //Escribo la información en el archivo
            end;
      //A continuación cierro los dos archivos
      close (Me.D);
      close (Me.C);
      {$I+}
end;

Procedure AbrirArbol (var Me : TipoArbol);
begin
      reset (Me.D);
      reset (Me.C);
end;

Procedure CerrarArbol (var Me : TipoArbol);
begin
      close (Me.D);
      close (Me.C);
end;

Function Raiz(var Me : TipoArbol) : TipoPosicion;
var
    registroControlAux : RegistroControlArbol;
begin
      seek(Me.C, valorNulo);
      read(Me.C, registroControlAux);
      Raiz := registroControlAux.Raiz;
end;

Function Padre(var Me : TipoArbol; pos : TipoPosicion) : TipoPosicion;
var
    registroDatosAux : RegistroDatosArbol;
begin
      seek(Me.D, pos);
      read(Me.D, registroDatosAux);
      Padre := registroDatosAux.Padre;
end;

Procedure CapturarNodo(var Me : TipoArbol; pos : TipoPosicion; var regDatos : RegistroDatosArbol);
begin
      seek(Me.D, pos);
      read(Me.D, regDatos);
end;

Procedure ModificarNodo(var Me : TipoArbol; pos : TipoPosicion; regDatos : RegistroDatosArbol);
var
    registroDatosAux : RegistroDatosArbol;
begin
      seek(Me.D, pos);
      read(Me.D, registroDatosAux);

      registroDatosAux.Padre := regDatos.Padre;
      registroDatosAux.HijoDerecho := regDatos.HijoDerecho;
      registroDatosAux.HijoIzquierdo := regDatos.HijoIzquierdo;
      registroDatosAux.Clave := regDatos.Clave;

      seek(Me.D, pos);
      write(Me.D, registroDatosAux);
end;

Procedure InsertarNodo(var Me: TipoArbol; pos : TipoPosicion; regDatos : RegistroDatosArbol);
var
    registroControlAux: RegistroControlArbol;
    posNueva: TipoPosicion;
    registroDatosAux, padre: RegistroDatosArbol;
begin
      Seek(Me.C, valorNulo);
      Read(Me.C, registroControlAux);

    if (registroControlAux.Borrado = posNula)
      then
          posNueva := FileSize(Me.D)
      else
          begin
                posNueva := registroControlAux.Borrado; //Tengo uno borrado, entonces lo recupero
                Seek(Me.D, posNueva);
                Read(Me.D, registroDatosAux);
                registroControlAux.Borrado := registroDatosAux.HijoDerecho //Para que pongamos siempre ese
          end;

    if (registroControlAux.Raiz = posNula) then //Significa que esta vacio
      begin
            registroControlAux.Raiz := posNueva;
            regDatos.Padre := posNula;    //
            regDatos.HijoIzquierdo := posNula;  // Para darle los nuevos enlaces que sino vienen con basura
            regDatos.HijoDerecho := posNula;  //
            registroControlAux.Cantidad := registroControlAux.Cantidad + 1;
      end
    else
         begin
              Seek(Me.D, pos);
              Read(Me.D, padre);
              if (regDatos.Clave <= padre.Clave)
                then //Para engancharlo
                    padre.HijoIzquierdo := posNueva
                else
                    Padre.HijoDerecho := posNueva;

              regDatos.HijoIzquierdo := posNula;
              regDatos.HijoDerecho := posNula;
              regDatos.Padre := pos;

              Seek(Me.D, pos);
              Write(Me.D, padre);
              registroControlAux.Cantidad := registroControlAux.Cantidad + 1;
          end;

    Seek(Me.C, 0);
    Write(Me.C, registroControlAux);
    Seek(Me.D, posNueva);
    Write(Me.D, regDatos);
end;


{Procedure InsertarNodo(var Me: TipoArbol; pos : TipoPosicion; regDatos : RegistroDatosArbol);
var
    registroControlAux : RegistroControlArbol;
    registroDatosAux : RegistroDatosArbol;
    posNueva : TipoPosicion;

begin
      seek(Me.C, valorNulo);
      read(Me.C, registroControlAux);

      if(registroControlAux.Borrado = posNula)
        then
            posNueva := filesize(Me.D)
        else
            begin
                  posNueva := registroControlAux.Borrado;
                  seek(Me.D, posNueva);
                  read(Me.D, registroDatosAux);
                  registroControlAux.Borrado := registroDatosAux.Padre;
            end;


      if(registroControlAux.Raiz = posNula)
        then // Inserto en árbol vacío
            begin
                  registroControlAux.Raiz := posNueva;
                  regDatos.HijoIzquierdo := posNula;
                  regDatos.HijoDerecho := posNula;
                  regDatos.Clave := claveNula;
            end
        else
            begin
                  seek(Me.D, pos);
                  read(Me.D, registroDatosAux);
                  if(regDatos.Clave <= registroDatosAux.Clave)
                    then
                        registroDatosAux.HijoIzquierdo := posNueva
                    else
                        registroDatosAux.HijoDerecho := posNueva;

                  regDatos.Padre := pos;
                  regDatos.HijoDerecho := posNula;
                  regDatos.HijoIzquierdo := posNula;
            end;

        seek(Me.D, pos);
        write(Me.D, registroDatosAux);

        registroControlAux.Cantidad := registroControlAux.Cantidad + 1;

        //Actualizo el archivo de control

        seek(Me.C, valorNulo);
        write(Me.C, registroControlAux);

        //Actualizo el archivo de datos

        seek(Me.D, posNueva);
        write(Me.D, regDatos);
end;    }

Function ArbolVacio(var Me: TipoArbol) : boolean;
var
    registroControlAux: RegistroControlArbol;
begin
      Seek(Me.C, valorNulo);
      Read(Me.C, registroControlAux);
      ArbolVacio := (registroControlAux.Raiz = posNula);
end;

Function HijoIzquierdo(var Me: TipoArbol; pos: TipoPosicion) : TipoPosicion;
var
    registroDatosAux: RegistroDatosArbol;
begin
      Seek(Me.D, pos);
      Read(Me.D, registroDatosAux);
      HijoIzquierdo := registroDatosAux.HijoIzquierdo;
end;

Function HijoDerecho(var Me: TipoArbol; pos: TipoPosicion) : TipoPosicion;
var
    registroDatosAux: RegistroDatosArbol;
begin
      Seek(Me.D, pos);
      Read(Me.D, registroDatosAux);
      HijoDerecho := registroDatosAux.HijoDerecho;
end;

Function Buscar(var Me: TipoArbol; clave: TipoClave; var pos: TipoPosicion) : boolean;
var
    registroControlAux : RegistroControlArbol;
    registroDatosAux :  RegistroDatosArbol;
    posicionPadre: TipoPosicion;
    encontre: boolean;
begin
      Seek(Me.C, valorNulo);
      Read(Me.C, registroControlAux);
      pos:= posNula;
      posicionPadre:= posNula;
      encontre := false;

      while( not(encontre) and (pos <> -1)) do
      begin
            Seek(Me.D, pos);
            Read(Me.D, registroDatosAux);
            if (clave = registroDatosAux.Clave)
              then
                    encontre := true
              else
                    begin
                          posicionPadre:= pos;
                          if (clave < registroDatosAux.Clave)
                            then
                                  pos := registroDatosAux.HijoIzquierdo
                            else
                                  pos:= registroDatosAux.HijoDerecho
                    end;
      end;

      //Para saber donde deberia estar
      if (not (encontre))
        then
            pos:= posicionPadre;

      Buscar := encontre;
end;

end.

Esta libreria, por ejemplo deberia usarla desde otra unidad donde modelo un ingreso de mascotas al sistema. El sistema modela una veterinaria.

El tema es que mi TipoDatoMascota es un registro con datos propios (nombre mascota, peso, edad, etc) y tengo que vincularlo de alguna forma con el registro de datos del arbol. Lo hice agregano una propiedad a ese registro de tipo RegistroDatoArbol, hasta ahi todo bien, el tema es que cuando quiero insertar un nuevo nodo con la libreria de arbol, lo inserta, pero no estoy pudiendo traer los datos propios de la mascota. Como la idea es reusar la libreria, creo que no es una buena opcion declarar los tipos propios de la mascota dentro del registro TipoDatosArbol, ya que esta misma libreria deberia usarla con otras unidades con otros datos totalmente distinto.

¿Alguien sabe como puedo modelar esta especie de genericidad?

Muchas gracias.

engranaje 10-02-2015 15:05:21

Parece puramente académico. ¿No se puede utilizar clases?. Lo pregunto porque si efectivamente como parece es un ejercicio y debe utilizarse los conocimientos adquiridos hasta el momento, bien es posible que aún no sepais nada de los objetos y debais "apañaros" con lo que sabeis. Igual no te sirve una solución que pase por declarar varias clases y utilizar herencia y polimorfismo para solucionar el problema aunque esa sea la mejor opción.

martin.lazzeri 10-02-2015 15:12:32

Lamentablemente no se pueden utilizar clases y nada orientado a objetos, es ahí que tengo el problema.

Neftali [Germán.Estévez] 10-02-2015 15:46:00

Cita:

Empezado por martin.lazzeri (Mensaje 488620)
Lamentablemente no se pueden utilizar clases y nada orientado a objetos, es ahí que tengo el problema.

:(:(

Justamente la solución es utilizar herencia.
Definir esos "elementos" que varían como clases y no como elementos fijos.

Revisa Genéricos, pero va a ser lo mismo...

duilioisola 10-02-2015 18:20:32

Se me ocurre utilizar punteros, pero eso complica un poco las cosas...
Hablo de memoria, pero sería algo así:
Código Delphi [-]
type
// Tipos de datos
TElemento = record
   id: integer
   tipo: string;
   dato: pointer;
end;

TAnimal = record
  nombre: string;
  peso: integer;
  edad: integer;
end

TPlanta = record
  especie: strnig
  aguanecesaria: integer;
end

// Punteros a tipos de datos
var
  PElemento: ^TElemento;
  PAnimal: ^TAnimal;
  PPlanta: ^TPlanta;
 
begin
  // Creo un elemento
  UnElemento := New(PElemento);
  UnElemento.id := 1;
  UnElemento.tipo := 'ANIMAL';
  // Creo un dato de tipo animal
  UnElemento.dato := New(PAnimal);
  PAnimal(UnElemento.dato)^.nombre := 'CHUCHO';
  ...
  // Creo otro elemento
  UnElemento := New(PElemento);
  UnElemento.id := 2;
  UnElemento.tipo := 'PLANTA';
  // Creo un dato de tipo planta
  UnElemento.dato := New(PPlanta);
  PPlanta(UnElemento.dato)^.especie := 'GRIASOL';
  ...
  // Libero memoria
  Dispose(UnElemento.dato);
  Dispose(UnElemento);
end;

engranaje 13-02-2015 12:27:48

Yo si he de ser sincero, tras leer tu descripción del problema y en base a lo que he entendido harías lo siguente para este caso en concreto y dando por sentado que para un caso genérico lo mejor sería crear los objetos necesarios y usar herencia.

Basandonos en tu tipo
Código Delphi [-]
type      
  RegistroDatosArbol = record                                   
    Clave : TipoClave;                                   
    Padre : TipoPosicion;                                   
    HijoDerecho : TipoPosicion;                                  
    HijoIzquierdo : TipoPosicion;                            
  end;

y en que tu
Cita:

TipoDatoMascota es un registro con datos propios (nombre mascota, peso, edad, etc)
Lo mejor sería que añadieras tu tipo TipoDatoMascota clave,padre,hijoDerecho e hijo izquierdo tal y como los tiene RegistroDatosArbol.

Despues deberias asegurarte de que tu TipoDatoMascota está definida en unit de tipos que pudieras añadir al uses de las units en la que vayas a usar y añadiria esa unit al uses de la unit Arbol.

Finalmente eliminina la declaración de RegistroDatosArbol de la unit Arbol y sustituye los sitios en los que se utiliza por TipoDatoMascota .

Deberias llamar a tu árbol "árbol de mascotas" ya que solo servirá para organizar records del tipo TipoDatoMascota pero deberas creo leyendo tu descripción del problema no necestias nada más porque en principio tu árbol solo va a ser usado para trabajar con tipoDatoMascota. Sospecho que posteriormente quien te esté enseñanado añadira la necesidad de poder utilizar el arbol (y los otros tipos de estrucutras de datos) para poder utilizar disintos tipos y no siempre el mismo y en ese punto comenzará a explicar los punteros o la orientación a objetos.

Creo que normalmente cuando alquien eseña a programar primero da pocas herramientas y despues pide que se ejerciten esas herramientas problemas que pueder solucionarse utilizandolas. Posteriormente se añaden complejidades que no pueden solucionarse con las herramientas que se conocen y se enseña una nueva herramienta para solucionar el problema. La orientación a objetos es la herramienta óptima para crear un árbol genérico. Los punteros y los tipos genéricos son herramientas que pueden utilizarse para conseguirlo si no se permite utilizar objetos. Pero siempre hay que aprender primero lo básico.


La franja horaria es GMT +2. Ahora son las 00:51:32.

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