Of course: If you have a hammer, everything looks like a nail...
So the question is: What kind of implementation should I use?
Let's collect some possibilities.
- Interface
- Class
- Record
- Methods in a Unit
OK - this makes no sense... Let me try this again from another point of view. Can you guess where this will lead us again?
You have a Form and you don't want to put your business code into this form. Ring a bell?
Where to store the code? Of course in a different unit, but that is not the point.
Every form needs data, so where do we get the data from?
We can get it from a database, but in my opinion, this is the worst way to use data-sensitive components.
We can create a unit with procedures and functions to pass the data or get the data. or we can create a class that can hold the data as well as read and store it.
But wasn't there a rule that a class should only do one task?
We should have separate classes or methods for saving and loading.
So first we need a storage structure that can hold the data we need for our input on our form.
We can go the old way with new and dispose or getmem and freemen.
We can use a record or a class. And if we need a list, we can use a TList<T> or a TArray<T>. or a linked list as in the old days?
Are you too young to know what a linked list is? Well then, here is a short explanation:
Assume you have a record and a Pointer
PFoo = ^TFoo;
TFoo = Record
PFoo = ^TFoo;
TFoo = Record
Name : ShortString;
Next : PFoo;
end;
Var
Root,
Akt,
NewFoo : PFoo;
begin
Root := NIL;
New(NewFoo);
Root := NewFoo;
Root.Next := NIL;
New(NewFoo);
Root.Next := NewFoo;
NewFoo.Next := NIL
Akt := Roo;
While Akt <> NIL do
begin
Writeln(Akt^.Name);
Akt := Akt^.Next;
end;
end;
You get the memory with New and you can easily iterate through the list. You have to free the memory with dispose.
Is it good or bad?
On the positive side: You do not need a contiguous memory block to store the data. Unfortunately, you do not have direct access to the nth element.
You can of course create the record with New and store the pointer in an array. This means you can access the nth element at any time. You only need a memoryblock for the size of n-pointer, but even in this case you have to release all elements with dispose. Let's ignore the smart records at this point.
A TList<TFoo> and a TArray<TFoo> again must fit a linear block of memory.
You can use a TObjectList with owns value to great your classes get destroyed.
You can use a TObjectList with owns value to great your classes get destroyed.
From all this I always come back to: TArray<IFoo>.
Why no link to the Implementation just to the Interface declaration and no problems with memory.
Why no link to the Implementation just to the Interface declaration and no problems with memory.
So happy coding...
In your article you ask: But wasn't there a rule that a class should only do one task?
ReplyDeleteSingle responsibility Principle states that : A class should have one and only one reason to change, meaning that a class should have only one job.
But in order to do this One Job the class might need to perform one or more taks.
For instance a TForm is a class representing a form object. Its job is to provide part of visual interface of your application that user can interact with. But in order to do this it needs to perform various tasks like rendering of Form window, notifying child components when it is being resized, or even notifying child components when the form is being destroyed.
So no the class usually doesn't have just one task but it usually does have one job.