Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   OOP y referencias circulares (https://www.clubdelphi.com/foros/showthread.php?t=37848)

AzidRain 24-11-2006 00:06:40

OOP y referencias circulares
 
Codificando un diagrama UML me paso algo raro con Delphi al tratar de hacer que las clases interactuen entre si ya me jaló.

La idea es para un catalogo de cuentas, la idea es la siguiente:

tengo la clase Catalogo que es diagamos el "corazon" de todo, a su vez esta clase contiene una clase TVentanaCat que es un TForm, y una clase TCuenta (TOBject). La interaccion de TCatalogo con TCuenta no tiene problema ya que TCatalogo se encarga de crear, manipular y destruir a TCuenta sin problema.

Ahora bien, TVentanaCat, es la parte "visual" de TCatalogo, o sea la forma que muestra en forma grafica las cuenta con la que esta trabajando en ese momento. El problema es que como TVentanaCat es parte de TCatalogo, para usarla debo poner un uses en TCatalogo. Por su parte TVentanaCat le tiene que pasar a TCatalogo los mensajes de lo que el usuario haya solicitado para que lo ejecute (recordemos que TVentanaCat solo es el "cascaron", no sabe como manipular una TCuenta). Ahi es donde entra el problema, para poder accesar a TCatalogo tengo que añadir un uses pero como en TCatalogo a su vez referencía TVentanaCat se crea una referencia circular que no es posible compilar.

La solución puede ser que TCatalogo y TVentanaCat sean el mismo objeto, es decir, incluir todo el código para manipular TCuenta dentro de TVentanaCat...pero no me parece muy elegante.

Otra opción es hacer a la inversa, que TVentanaCat sea la clase de más alto nivel y que contenga a TCatalogo para manipularlo...pero tampoco se me hace muy elegante.

En Java si puede hacerse como lo estoy tratando sin problemas, pero no quiero usarlo porque swing no ofrece tanta calidad como las VCL y otros componentes que ya tengo de Delphi.

Siempre he diseñado usando programación mixta: procedural y OOP, pero ya me quiero "ordenar" y usar solo OOP.


Como me recomiendan hacer el diseño?

roman 24-11-2006 00:55:16

No sé yo si esto te pueda servir. La idea es que dos unidades pueden usarse una a la otra siempre y cuando no sea ambas en la parte de interface. En el ejemplo que te pongo factorizo por una tercera unidad común que ambas llaman desde su parte interface. Esta unidad común contiene interfaces a las clases, pero no implementan nada. Cada unidad Catalogos y Ventanas usan esta unidad común para poder declarar sus propiedades en la parte interface. Pero es en la parte implementation donde cada una llama a la otra para poder construir realmente el objeto que implementa la interfaz.

Código Delphi [-]
// Intf.pas

unit Intf;

interface

type
  IVentana = interface;

  ICatalogo = interface
    function GetVentana: IVentana;
  end;

  IVentana = interface
    function GetCatalogo: ICatalogo;
  end;

implementation

end.
-------------------------------------------------------------------------------

// Catalogos.pas

unit Catalogos;

interface

uses
  Intf;

type
  TCatalogo = class(TInterfacedObject, ICatalogo);
  private
    FVentana: IVentana;

  public
    function GetVentana: IVentana;
    constructor Create;
  end;

implementation

uses
  Ventanas;

function TCatalogo.GetVentana: IVentana;
begin
  Result := FVentana;
end;

constructor TCatalogo.Create;
begin
  FVentana := TVentana.Create;
end;

end.
-------------------------------------------------------------------------------

// Ventanas.pas

unit Ventanas;

interface

uses
  Intf;

type
  TVentana = class(TInterfacedObject, IVentana);
  private
    FCatalogo: ICatalogo;

  public
    function GetCatalogo: ICatalogo;
    constructor Create;
  end;

implementation

uses
  Catalogos;

function TVentana.GetCatalogo: ICatalogo;
begin
  Result := FCatalogo;
end;

constructor TVentana.Create;
begin
  FCatalogo := TCatalogo.Create;
end;

end.

Ahora, al margen de esto, pienso que es un poco raro que una clase, TCatalogo se encargue de su propia representación visual. De alguna manera esto la hace dependiente de la parte visual, cosa que no se recomienda. Quizá te convendría factorizar por un tercer objeto que se encargue de crear la ventana y pasarle los datos de un objeto TCatalogo.

// Saludos

AzidRain 24-11-2006 03:56:08

Finalmente obté por algo muy parecido a lo que comentas al final...Le di a la ventana métodos para que pueda manipular el TCatalogo, es decir, mostrarlo, añadirle o quitarle cuentas, etc. pero de manera visual. Si cambio el catálogo no afecta a la ventana pues esta solo le manda mensajes tipo "Borracuenta(numCuenta)" o "ObtenCuentas". Lo hice así mas que nada porque la ventana en cuestion, tendrá algo de interactividad que requiere estar actualizando cosas a TCatalogo. El TCatalogo lo crea en este caso la aplicación principal y se lo pasa a la ventana para que lo manipule, una vez cerrada la ventana la aplicación lo destruye.

Mira que simple se vuelve el código cuando lo ve uno así, si lo hubiese hecho como antes me hubiera quedado un rollazo de n lineas, así como voy me quedan métodos pequeñitos de unas cuentas líneas y que decir de como se puede leer el código...

grax


La franja horaria es GMT +2. Ahora son las 07:22:25.

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