jueves, 28 de diciembre de 2017

Componentes e interfaces (finales distintos)

Finales distintos

Los componentes y las interfaces tienen mecanismos de destrucción diferentes. Los componentes tienen un mecanismo de destrucción automático basado en el dueño (Owner) Las interfaces tienen un mecanismo de destrucción automático basado en la cantidad de referencias vigentes.

Componentes

Cuando creamos un componente (una instancia de la clase TComponent o descendiente) el constructor recibe un parámetro de entrada de tipo TComponent. Si le pasamos nil entonces tendremos que encargarnos de destruir la instancia creada. Si le pasamos un objeto entonces cuando dicho objeto sea destruido se encargará de destruir las instancias de todos los objetos de los cuales es el dueño.

procedure TMiForm.DoMiComponente;
var
  oMiComponente: TMiComponente;
begin
  oMiComponente := TMiComponente.Create(Self);
  oMiComponente.Free;
end;

En el código anterior se crea una instancia de la clase TMiComponente y se mantiene una referencia a dicha instancia en la variable oMiComponente. Luego, a través de la referencia mantenida en dicha variable, se destruye la instancia. Como el Owner de la instancia de TMiComponente es Self, es decir, la instancia de TMiForm, si no destruyéramos explícitamente la instancia de TMiComponente, ésta sería destruída implícitamente al destruir la instancia de TMiForm.

Interfaces

Cuando creamos una instancia de una clase que implementa una interface y obtenemos referencias a la interface, internamente se lleva la cuenta de la cantidad de referencias vigentes. Cuando dicha cantidad llega a 0, es decir, ya no hay referencias vigentes, la instancia de la clase puede ser destruida. El código responsable de hacerlo es insertado automáticamente por el compilador y no tenemos ningún control sobre el mismo.

procedure TMiForm.DoMiInterface;
var
  oMiInterface: IMiInterface;
begin
  oMiInterface := TMiInterface.Create as IMiInterface;
  oMiInterface := nil;
end;

En el código anterior se crea una instancia de la clase TMiInterface que implementa la interface IMiInterface y se obtiene una referencia a dicha interface que se mantiene en la variable oMiInterface. Cuando dicha referencia deja de estar vigente, en este caso al asignarle nil, la instancia será destruida por el código insertado por el compilador. Si no le asignáramos nil a la variable oMiInterface, la referencia dejaría de estar vigente al finalizar la ejecución del método DoMiInterface porque la variable es local para dicho método.

Un ejemplo

Veamos un ejemplo muy simple.

type
  IMiInterface = interface(IInterface)
  ['{F0E8209C-4D47-46C5-B28F-D19ACEEC9552}']
    procedure DoMiMetodo;
  end;

  TMiObjeto = class(TInterfacedObject, IMiInterface)

  { IMiInterface }
  protected
    procedure DoMiMetodo;
  { IMiInterface }

  public
    destructor Destroy; override;
  end;

  TfrmMiForm = class(TForm)
    btnMiMetodo: TButton;
    procedure btnMiMetodoClick(Sender: TObject);
  end;


En la sección Interface, primero declaramos la interface, luego la clase que implementa la interface y finalmente el Form (la parte del Form la hace Delphi)

{ TfrmMiForm }

procedure TfrmMiForm.btnMiMetodoClick(Sender: TObject);
begin
  (TMiObjeto.Create as IMiInterface).DoMiMetodo;
end;

{ TMiObjeto }

destructor TMiObjeto.Destroy;
begin

  inherited;
end;

procedure TMiObjeto.DoMiMetodo;
begin
  ShowMessage('MiMetodo');
end;


En la sección Implementation implementamos los métodos. La implementación del método Destroy es sólo para poner un breakpoint y ver cómo el código insertado por el compilador destruye la instancia de TMiObjeto.

TInterfacedObject

Para que todo esto sea posible es necesario que la clase que implementa la interface descienda de la clase TInterfacedObject, que es donde se implementa el mecanismo de destrucción automático basado en la cantidad de referencias vigentes.

Descargar proyecto Delphi 2010

No hay comentarios:

Publicar un comentario