[DUG] Discussion & Donation

Kyley Harris kyley at harrissoftware.com
Mon May 15 13:47:32 NZST 2006


Todd:

Yep. I have done similar things in a few cases. 

 

The main reason not to in this scenario is because it is designed to be
generic, and doesn't know how many types of classes will call it, or how
many message types may exist.

 

The main reason for either string, or integer is for scalability of use.
I personally just like strings :-) I think most would go your way and
use integer codes the way windows does. 

 

C(K)arl :

 

I have removed all use of interfaces from my code. Simple reasons. I
have found the compiler does not do its job properly all the time and
gets memory unthread-safe errors in dealing with de-referencing
properly. My old code used interfaces for all the notification. An I had
code generators that inserted the code quickly and easily. But from a
design point of view, this new method of doing it, is Faster, easier,
less memory hungry when you use it for entire application notification.
Its just an evolutionary step for me that has made my life easier. The
sample I provided doesn't really do justice to the dozens and dozens of
applications. Also. When you use the interfaces for everything. It's a
big refactor if you were wrong in your design.

 

Stefan & Todd:

 

List := TStringList.Create;

List.CaseSensitive := false;

List.Sorted := True;

List.Duplicates := false;

 

List.Add(a);

....

 

I := List.indexof(Value)

 

Very fast. Indexed. Loops are always slow. 

 

 

________________________________

From: delphi-bounces at ns3.123.co.nz [mailto:delphi-bounces at ns3.123.co.nz]
On Behalf Of Todd Martin
Sent: Monday, 15 May 2006 12:55 p.m.
To: NZ Borland Developers Group - Delphi List
Subject: Re: [DUG] Discussion & Donation

 

3) Okay. Good point. I didn't pick up on this, as you hadn't marked the
procedures as virtual, but I guess that can always be added later
without breaking existing code.

 

4) Have you considered RegisterIntegerConsts() for converting message
integers to text?

Or failing that I often use something like this

 

type

TMessageType = (mtUnknown,mtChange,mtSave,mtLoad)

 

const

   MessageTypeToText : array[TMessageType ] of string =
('Unknown','Change','Save','Load');  

 

That way, whenever I add an enumeration, I have to also add an
equivalent string description.

To convert the text back to an enumerated type, I just use a standard
procedure to find the index of the text in the array. By making the
first enumeration unknown/default I always get a meaningful result when
casting the integer back to a type.

 

Type := TMessageType(IndexOf(MessageText,MessageTypeToText);

 

function IndexOf(AName : String; AStringArray : array of string) :
Integer;
var
  NameIndex, FoundIndex : Integer;
  CurrentName : String;
begin
  NameIndex := 0;
  FoundIndex := 0;
  while (NameIndex < length(AStringArray)) and (FoundIndex = 0) do
  begin
    CurrentName := AStringArray[NameIndex];
    if SameText(AName,CurrentName) then
    begin
      FoundIndex := NameIndex;
    end;

 

    inc(NameIndex);
  end;

 

  Result := FoundIndex;
end;

 

 

However, I see your point about streaming numbers to XML

     

Todd.

 

	----- Original Message ----- 

	From: Kyley Harris <mailto:kyley at harrissoftware.com>  

	To: NZ Borland Developers Group - Delphi List
<mailto:delphi at ns3.123.co.nz>  

	Sent: Monday, May 15, 2006 11:05 AM

	Subject: RE: [DUG] Discussion & Donation

	 

	Thank.

	Point 1/ Fair enough

	Point 2/ correct . I had written that bit early on before I
realized I could break it down correctly with TMethdo.code and
TMethod.Data and I haven't fully refactored it yet. I've removed it now.

	Point 3/ Because you cant do anything with a bunch of
procedures. Ie it is not portable. Class functions can be overridden.
You don't need to use TNotifier.AddListener,

	 You could have for example add a meta class and a classvariable
to the global, Var NotifierClass:TNotiferClass = TNotifer. I then use
this for accessing the functions and down the track in some cases or
applications you may wish to modify how it works, without effecting All
the other apps by simply changing the class pointer. static procedures
do not lend themselves to upgrading software without breaking old
software and this is one of the most powerful uses of static classes as
libraries that many people in Delphi don't take advantage of. 

	Point 4. I use constants, so I don't have typos in message names
(except for demos). And I use SameText, so they are not case-sensitve. I
do this purely because I prefer debugging meaningful strings rather than
integers. It also makes It easier when dealing with storage of types etc
in human readable XML. So that's why I do it. Many books use integers. I
just don't like it. Also. A lot of my infrastructor permits streaming of
the entire message, and the data object over TCP as part of the
notification. I prefer unknown apps receiving this to get a meaningful
'CLIENT_OBJECT_UPDATED' rather than 3 ;)

	 

	The StringList is indexed, and its very fast, I've tested with
thousands of binds with no real time effect. The work done by listeners
is the time issue. Not the lookup.

	 

	 

	I used to have an observer and observed class system too. And it
was really annoying when you had to make changes. I even wrote a plugin
for the IDE to convert an object into a listener etc by inserting all
the code for me. So that took the hassle out. But I prefer the decoupled
method. 

	 

	Thanks for the feedback. 

	 

	
________________________________


	From: delphi-bounces at ns3.123.co.nz
[mailto:delphi-bounces at ns3.123.co.nz] On Behalf Of Todd Martin
	Sent: Monday, 15 May 2006 10:38 a.m.
	To: NZ Borland Developers Group - Delphi List
	Subject: Re: [DUG] Discussion & Donation

	 

	Well you said you wanted feedback, so I hope this isn't too
picky.

	 

	1) I find the inconsistent use of variable prefixes a bit
annoying. I tend to stick with

	F- class field

	A - method parameter

	P - pointer

	and no prefixes for class properties or local variables.

	 

	2) TListenerItem.FListener is redundant, since the information
it contains is already held in TListenerItem.FBindMethod

	It could have been implemented as a function, but I don't see
why it is needed.

	As usual, redundancy leads to complication elsewhere

	 

	eg.  if (MethodEquals(TMethod(Items[i].FBindMethod)
,TMethod(ABinder))) and (Items[i].FListener = AListener) then

	 

	the second condition is automatically satisfied by the first
condition.

	 

	3) Why define a TNotifier class when all its methods are static?
They could be defined as simple procedures/functions in the unit.

	 

	4) I'm not keen on the idea of passing a string parameter to
identify the message type, for the simple reason that spelling mistakes
can arise and you're never really sure at compile time what "messages"
are being broadcast/handled. This problem can of course be ameliorated
through the use of constants, but I prefer the use of an enumerated
type.

	 

	Having said all that. I like the loose coupling of your
solution. I have implemented the observer pattern previously with the
lists maintained internally by the objects involved, so removing the
need to inherit from a particular class is a great improvement. I hadn't
considered that option before. Of course you do pay a miniscule
performance penalty in having to find the correct list for the object.
Perhaps the use of THashedstringlist could mitigate this further.

	 

	Todd.

	 

	 

		----- Original Message ----- 

		From: Kyley Harris <mailto:kyley at harrissoftware.com>  

		To: NZ Borland Developers Group - Delphi List
<mailto:delphi at ns3.123.co.nz>  

		Sent: Wednesday, May 10, 2006 3:36 PM

		Subject: [DUG] Discussion & Donation

		 

		In an attempt to create some more interesting
discussion, other than talking about the crud IDE issues, I am donating
some useful code for discussion, rather than for help. Feel free to
keep/use the code if you want to. Be mean if you feel the need (but if
your personal then watch out ;) Hopefully this may introduce a
discussion where people learn something, or are able to contribute some
interesting ideas/information about the topic (which is object
notification and observation).

		 

		In the attached zip is a sample application showing a
basic, but horrible use of the class in uNotifier.pas. TNotifer is a
class I wrote a long while back which loosely follows an observer
pattern for allowing one-to-many observations between an object, and a
bunch of interested object. 

		 

		The main difference this class has between many observer
patterns is that you do not have to modify existing classes, or
sub-class anything, or instantiate anything in your existing objects.
The TNotifier handles all the bindings, you just need to implement one
listening event on each listening object.

		 

		The sample app is a corny app that makes child forms
(button click) update a memo based on changes to the memo on the main
form. God help me if I ever did anything as potentially unthread safe as
that in a real app.

		 

		Fun fun fun.... (I hope the app compiles. You never know
with these tricky little sample apps)

		
________________________________


		_______________________________________________
		Delphi mailing list
		Delphi at ns3.123.co.nz
		http://ns3.123.co.nz/mailman/listinfo/delphi

		
________________________________


		Internal Virus Database is out-of-date.
		Checked by AVG Free Edition.
		Version: 7.1.385 / Virus Database: 268.5.1/327 - Release
Date: 28/04/2006

	
________________________________


	_______________________________________________
	Delphi mailing list
	Delphi at ns3.123.co.nz
	http://ns3.123.co.nz/mailman/listinfo/delphi

	
________________________________


	Internal Virus Database is out-of-date.
	Checked by AVG Free Edition.
	Version: 7.1.385 / Virus Database: 268.5.1/327 - Release Date:
28/04/2006

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://ns3.123.co.nz/pipermail/delphi/attachments/20060515/58f6380e/attachment-0001.html


More information about the Delphi mailing list