Gareth Conner wrote:
> Thanks for the example, that does look like my first attempt. As you
noted,
> where I tripped up was using TObjectList. I then found TInterfaceList, but
> decided to abandon interfaces since the more I read about their use in
> Delphi, the more spooked I became. As you say, they are certainly a
> different beast than interfaces in Java or C#.
>
you /might/ find this post helpful...
http://groups.google.com/group/borland.public.delphi.oodesign/msg/cf5a4182329d70
d3
and some dependent code...
|
Joanna,
Thanks very much for your detailed response. I'm replying to the
b.p.d.oodesign group to move the discussion to a more appropriate group. I
hope this is the correct protocol for shifting newsgroups, my apologies if
I've made a faux pas (discussion started in b.p.d.l.d.general).
> Simple Observer pattern :
>
> IObserver = interface
> [GUID] // you must add a GUID to make interfaces work.
> procedure Update(const subject: IInterface);
> end;
>
> ISubject = interface
> [GUID]
> procedure AddObserver(const observer: IObserver);
> procedure RemoveObserver(const observer: IObserver);
> procedure Notify();
> end;
>
> Now, you need to derive from TInterfacedObject to make reference counting
> work correctly, and you must use TInterfaceList to store lists of
> interface references; TObjectList is not suitable as it breaks reference
> counting and you will get either premature release of instances or memory
> leaks.
Thanks for the example, that does look like my first attempt. As you noted,
where I tripped up was using TObjectList. I then found TInterfaceList, but
decided to abandon interfaces since the more I read about their use in
Delphi, the more spooked I became. As you say, they are certainly a
different beast than interfaces in Java or C#.
> You can certainly cast an object to an interface, preferably using the
> 'as' operator, but beware, mixing interface and object references to the
> same instance can cause all sorts of problems due to reference counting vs
> deterministic finalisation.
OK, that's good to know. My casting problem appears to have been caused by
a slightly strange behavior that is exhibited by TList derivatives when
using the for..in loop structure. The returned type is appears to be a
pointer, but can in fact be directly cast to an object without dereferencing
(Rob Kennedy point out that this is a bug 10790 in QC).
Your warning of mixing interface and object references to the same instance
sounds perhaps a bit scary. I'm glad to get the warning now, as that
distinction is not exactly clear from Help file surfing. I'm sure the
information is there, but it would be appropriate to have a large red
warning label :-)
>> I found TInterfaceList, which solved my problem but made me curious as
to
>> what was so different between classes and interfaces in Delphi. Whoa!
I
>> found myself knee-deep in discussion of GUID's, reference-counting, and
>> COM.
>
> So now you know why most of us who use interfaces in Delphi suffer
> premature signs of aging :-)
Indeed, it's beginning to become clear :-)
>
> BTW, when passing either string or interface parameters to methods, you
> should prefix them with const to avoid extraneous reference counting on
> the way in/out of the method.
Thanks for that tip.
> As others have said, you don't need to use pointers or indirection in
> Delphi, all objects are implicitly pointers.
Yes, but it looks like I stumbled upon a weird bug that does require the use
of pointers when iterating over a TObjectList using the for..in construct
(at least in Delphi Turbo Pro 2006). For example:
//Listeners is a TObjectList
procedure TStringModel.add(NewString: String);
var
I : Integer;
listener : TObserver;
ptr : ^TObject;
begin
List.Add(NewString);
//this works
for ptr in Listeners do begin
//have to perform a cast without dereferencing
listener := TObserver(ptr);
listener.notify;
end;
//this throws a compiler error
//[Pascal Error] Unit1.pas(73): E2010 Incompatible types: 'TObserver' and
'Pointer'
for listener in Listeners do begin
listener.notify;
end;
end;
>
> Another BTW, the Delphi standard for interface names is to use I as a
> prefix, only use T for classes, unless yiou really want to confuse
> inveterate Delphi programmers.
Thanks, it all looks a little foreign at first, but the convention is
growing on me.
> I certainly use the Observer pattern as part of my MVP (Model View
> Presenter) frameworks, but, you need to be aware that it may involve
> sub-classing VCL controls in order to implement the IObserver interface,
> but that can also cause ref-counting problems!!! I eventually decided to
> use Adapter classes that implemented the intefaces and talked to the
> controls.
Excellent point. This is exactly the road that I was heading down, to
subclass VCL controls and implement the IObserver interface. But the creepy
memory management issues between interfaces and classes gave me pause. When
using Adapter classes, is there any need to use interfaces? Could you just
derive all adapters from and abstract super class?
> Please consider continuing this dicussion in the oodesign group, there is
> a whole wealth of knowledge there.
>
> Joanna
OK, this reply should be heading to a more appropriate group.
-Gareth
|