PDA

Ver la Versión Completa : Interfaces...


OscarG
11-10-2005, 15:51:45
Bueno, tengo otra serie de preguntas sobre interfaces, anteriormente tb hice unas preguntas, creo q en otra zona, pero creo q es aqui donde está mejor.

En principio tengo esta pregunta, a ver si alguien me podría contestar...

Creo este objeto...
Defino la clase

type
TMusica = class(TInterfacedObject, ITratarSonido )


La cosa es q creo el objeto Musica y le asigno la interfaz de esta forma:

Musica:= TMusica.Create(Self);
IMusica:= Musica as ITratarSonido;
comp1.setSonido(IMusica);


comp1 es un objeto cualquiera q tiene q manejar la música através de su interfaz...


procedure TComponente1.setSonido(val: ITratarSonido);
begin
isonido:= val;
end;


Aqui ya he hecho algo fatal, xq casca...me gustaría saber cómo hacerlo...

Gracias de antemano...

roman
11-10-2005, 17:18:42
¿Qué tipo de variable es Musica? Parece ser que es de tipo TMusica y que IMusica (mal nombre para una variable, por cierto) es de tipo ITratarSonido.

Lo adecuado es que Musica sea de tipo ITratarSonido y le asignes directamente el objeto creado:


var
Musica: ITratarSonido;

begin
Musica := TMusica.Create(Self);;
end;


sin pasar por una variable de tipo TTratarSonido intermedia.

// Saludos

OscarG
11-10-2005, 17:53:02
Como siempre, pongo variables y no digo pa q son...

Aunq en este caso, al no haber utilizado nunca interfaces, no se muy bien cómo llamarlos.

Me explico...

//TMusica es la clase q tiene el interfaz la interfaz.
//IMusica: es la interfaz de tipo ITratarSonido
//Musica: es de tipo TMusica
//comp1: Es un objeto TComponente1.
var
Musica: TMusica;
IMusica: ITratarSonido;
comp1: TComponente1;


El problema es con

comp1.setSonido(IMusica);


en este método me casca, y el caso es q tengo q pasárlo a otros objetos, y quería pasarlo por medio de la interfaz, aunq no se si se puedo, lo podría hacer de otro modo, pero me gustaría hacerlo con interfaces.

OscarG
13-10-2005, 09:32:55
Investigando, creo comprender un poco más los interfaces, claro, yo normalmente los utilizo creando un objeto y teniendo en cada objeto una interfaz única.
Yo ahora lo q busco, es crear una interfaz para varios objetos, entonces se me plantea la duda de si es posible o no...

También estoy pensando en la posibilidad de q crear una interfaz para lo q quiero, no es la mejor manera, ya q, pensandolo bien, no tendría mucho sentido, igual es una referencia al objeto lo q necesito. Ya q todos los objetos tienen q tener un referencia a un único objeto q controla la música.

Pos eso, yo por ahora voy a quitar la interfaz, pues cada vez estoy más seguro, me gustaría saber vuestra opinión para saber un poquito más.

Gracias!

rounin
13-10-2005, 13:41:20
Me parece que mezclas referencias a objeto y a interfaz.
Es no buena idea, porque tienen maneras diferentes de
manejo del tiempo de la vida.

Si usas objeto que soporta las interfaces,
debes usar o solo referencias al objeto,
o solo referencias a las interfazes del objeto.

?Que es razon de usar las interfaces en tu caso?
Variantes possibles:
1) para trabajar con objetos de clases diferentes sin ancestro comun,
que soporten el mismo interfaz.
2) para manejar automaticamente del tiempo de la vida del objeto
3) para simular herencia multiple
4) para transpasar el confín de exe/dll
5) para simular mix-in clases
6) ?

roman
13-10-2005, 17:04:52
Hola rounin,

¿podrías explicar un poco a qué te refieres con (5) y (6)?

// Saludos

OscarG
13-10-2005, 17:11:31
Bueno, es algo complejo. Estoy haciendo una especie de motor q controle el comportamiento de cualquier juego q realice.
Entonces se supone q lee de un fichero xml y va cargando los distintos objetos necesarios (botones, animaciones, cajas de texto,...), ninguno de estos objetos son los q utiliza delphi como componentes ya q utilizo las DelphiX como librería grafica y no es muy compatible, aunq si posible...

Bueno, entonces mi intención es llegar a controlar cada objeto através de interfaces, de tal forma q a la hora de tratarlos, no se sepa conq objeto se está tratando, sólo le dice cosas a los objetos, como q se ha producido un evento o ha recibido una orden, etc. (ellos ya sabrán lo q hacer)
Por ahora la primera parte de interfaces q tenía pensado me ha ido bien, pero mis siguientes intentos han fracasado.
En este caso, estoy ya casi convencido de q usar interfaces para el sonido no es conveniente ya q sería un objeto sonido para todos los objetos, por ejemplo si tengo un botón, en el caso de tener sonido, entonces, lo q he hecho es mandar un puntero del objeto sonido a el objeto botón y luego mediante el puntero puedo acceder al objeto sonido y poder cargar una canción, pararla, etc.

El problema creo q ha sido q al descubrir la utilidad de las interfaces me he emocionado, y lo he querido meter hasta en la sopa, pero claro, lo único q he recibido son bofetadas, una tras otra, y al final he visto lo equivocado q estaba o eso creo.

Aún asi, no las entiendo del todo, reconozco q son muy útiles, por lo menos para lo q quiero, vienen de perlas, pero sin olvidar q la herencia y otras cosas también tienen su peso y q no tengo q confundirme entre lo q quiero hacer y el método a utilizar.

Pos eso, sólo una pregunta, se puede mandar una interfaz como parámetro o eso viola alguna de las reglas de las interfaces?
Quiero decir, q si quiero pasar una interfaz a un objeto para q la controle, se podría hacer?. En el ejemplo q he mostrado, es un objeto q pertenece a otro objeto el q quiero q maneje la interfaz. Osea q hago un procedimiento q pasa como parámetro la interfaz. ¿Es una burrada?


procedure setSonido(val: ITratarMusica)
begin
musica:= val; //donde musica es de tipo ITratarMusica
end;


Hay alguna forma de hacerlo?

pos eso, muchas gracias por la ayuda

jachguate
13-10-2005, 18:31:24
Reconozco que no he leido todo el hilo, pero a primera vista me parece que básicamente se ha dicho:

Hay alguna forma de hacerlo?

Con esto mas

me casca

Así sin mas, sin saber si es en tiempo de compilación o de ejecución, el mensaje de error generado, la clase de la excepción (si hay una), etc (para mas referencia ver aqui), pues yo diría que es muy dificil hacerse la idea de que pueda estar ocurriendo.

Hasta luego

;)

OscarG
14-10-2005, 10:25:56
Creo q con eso me has respondido

Porq más o menos la pregunta era si podía hacer ese método, pasar una intefaz como parámetro, y entonces he empezado a pensar q era posible al no entender la pregunta o pensar q era algo tan obvio q no se vé y también xq no se preguntar, la verdad es q me cuesta mucho, pero no creas q no he investigado antes de preguntar, lo de los interfaces llevo unos meses tocandolos y sabiendo q me faltan cosas, en la documentación q he conseguido, no me parecía claro.

La próxima vez, espero se más claro y quizás pasar un ejemplo completo de mi fallo.

Bueno, pues he mirado mejor todo mi código y al final me ha funcionado (mas o menos), tenía una cosa mal y no lo había visto.

Gracias por las molestias y un saludo.

rounin
14-10-2005, 13:26:57
Hola, roman,
(6) I meant that I could forget about something :)

(5)
Mix-in classes is particular case of the multiple ihneritance.
When you don't want to use interface references,
and don't need the automatic life time management,
but want to add to your classes some different
orthogonal functionalities.

Mix-in interfaces allow make the interface of the base class compact.


type
//Base class for mix-in support. Disables reference counting
TMixInBase = class(TPersistent, IUnknown)
public
function TInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
//const E_NOINTERFACE = HResult($80004002);
//begin
// if GetInterface(IID, Obj)
// then Result := 0
// else Result := E_NOINTERFACE;
//end;
function TInterfacedObject._AddRef: Integer;
//begin
// Result := -1;
//end;
function TInterfacedObject._Release: Integer;
//begin
// Result := -1;
//end;
end;
TSomeBaseObject = class(TMixInBase)
{...}
end;

{----------------------------------------------------------------------------}

// Some of descendant of the TSomeBaseObject have name, other don't have.
IName = interface
['{D1693279-7EEA-417B-BCFC-BD7DC29E2763}']
function GetName: string;
procedure SetName(const AName: string);
end;

// Some of descendant of the TSomeBaseObject can create clone
ICloneable = interface
['{8990AA78-364E-4BFA-B444-CF12608D39FF}']
function Clone: TSomeBaseObject;
end;

// Some of descendant of the TSomeBaseObject can write their data to a stream
IStreamable = interface
['{3B83C00D-85E0-4CDC-B757-549592C756FA}']
procedure SaveData(Dest: TStream);
procedure LoadData(Src: TStream);
end;

// Some of descendant of the TSomeBaseObject have child objects
TChildProc = procedure(Child: TSomeBaseObject) of object;
IComposite = interface
['{07CB94B4-231F-41FF-B51E-1570D69966C5}']
procedure GetChildren(Proc: TChildProc);
end;

// Some of descendant of the TSomeBaseObject have an active area
IHitTest = interface
['{4279B456-5749-44CB-BCBF-B2FFEF0CCB15}']
function HitTest(const Point: TPoint): Boolean;
end;

TSomeDescendant = class(TSomeBaseObject, IName, ICloneable, IStreamable)
{...}
end;

TOtherDescendant = class(TSomeBaseObject, IComposite, IStreamable)
{...}
end;

{----------------------------------------------------------------------------}

// When you work with mix-in interfaces, you must use only local
// variables and must never save interface references in the
// global variables or object members.
// For example:

function GetName(Obj: TSomeBaseObject): string;
var intf: IName;
begin
if Obj.GetInterface(IName, intf)
then Result := intf.GetName
else Result := '';
end;

function Clone(Obj: TSomeBaseObject): TSomeBaseObject;
var intf: ICloneable;
begin
if Obj.GetInterface(ICloneable, intf)
then Result := intf.Clone
else raise Exception.Create('Object does''nt support ICloneable');
end;