Many Delphi programmers build applications through alot of components.
While this may be good on some cases( try doing DevExpress things without
using components :-) ) other times plain classes will do just well.
The reason many programmers don't use classes is that they relate OOP to
components wich - imho - is incorrect.
Classes can be very useful for run-time tasks where you need extensibility and polymorphism.
Encapsulation just comes in the bundle, if you do proper OOP.
Let's see an example: say you have to make a program that process text commands.
You could do it in this way:
Type
TCommandProcessor = class
protected
procedure ProcessCommand( S : String );
public
procedure LoadCommandsFromStream( S : TStream );
procedure LoadCommandsFromFile( const FileName : String );
end;
Then go on implementing it this way, with your ProcessCommand method getting *HUGE* and
unmantainable when time goes by. Now let's have a look at a, imho, better design:
Type
IMyCommandSource = interface
function GetNextCommand : String;
end;
TCommandBase = class
protected
procedure InternalProcessCommand( ACommand : String );virtual;abstract;
public
constructor Create;virtual;
procedure ProcessCommand( ACommand : String );
end;
TCommandClass = class of TCommandBase;
This acts as a base class for all commands. The Create constructor is
marked virtual( please do remember to call "Inherited Create" at some point in it ), so
that you can do there all of your command-wide initializations.
Using a protected method to make the actual process is senseful because that way you
won't need to change public methods when changing internal implementation.
We also defined an ICommandSource interface, this way *anything* implementing that
will be able to be passed along as a parameter when we'll use the interface.
Now we can create a list of commands:
Type
TCommandItem = class
public
property Name : String;
property CommandClass : TCommandClass;
end;
TCommandList = class
private
FList : TObjectList;
public
procedure AfterConstruction;override;
destructor Destroy;override;
procedure AddCommand( Name : String;ACommand : TCommandClass );overload;
procedure AddCommand( AnItem : TCommandItem );overload;
property Item[ Index : Integer ] : TCommandItem;
property CommandByName[ Index : Integer ] : TCommandClass;
end;
Now, you might want to make this a singleton, to share the same instance throughout
your program. Using CommandByName you can write something like this:
var Cmd : TCommandBase;
begin
Cmd := MyCommandList.CommandByName[ 'MyWeirdCommand' ].Create;
end;
Quite handful, uh?
Now you can build your command processor, using ICommandSource to get your
next command and then splitting the whole thing using a delimited string list.
Since Delimiter and DelimitedText only work for D6+ as far as I can recall, then you
might be well served using the CommaText property and have comma separated
commands.
The first string in your list will usually be the command, during processing you'll be
able to set relevant properties and be well.
Using a solid class-oriented architecture will save you big time when you'll be
adding new commands.
Needless to say, you may want to add your own event handlers, so that your
program can react to specific things happened or going to happen.
This wasn't a complete program on purpouse, just because I wanted to throw some
hints about paths you may want to explore.
It's up to you.
Cheers
3 comments:
I don't understant how the IMyCommand interface fits in the design?
I've been reading quite a bit about interfaces, but I dont' get it. What's so great about them? I know you need them for the COM stuff, but some people seems to think they're the greatest addition to Delphi since... well since Delphi 3 I guess.
To Anonymous:
Ok, to let you understand the power of interfaces, think of this example.
Say that during time, you had developed a class that retrieves data from a serial port, a file class and a TCP/IP socket class. Now, if you implement the same interface in all of them, you can seamlessly substitute any of them to the other and switch your command retrieval to any source, disregarding if all the classes were inherited from the same base.
This approach will save you time in that your classes can be derived from the one you need and then be made compatible with other parts of the system through interfaces' usage.
Cheers,
Andrew
(non Visual) Components are useful when using visual tools like the object inspector, wizards, component editors and property editor.
But I have to accept that components add several bytes to executables...
I had some programs with some of my custom Non-Visual components in a DataModule.
I had to migrate them from Delphi
to C++, and, of course, had to
change to plain classes...
cheers !!!
mramirez (at) star (minus) dev (dot) com
Post a Comment