I'm a Delphi pascal programmer, I use the latest Embarcadero delphi XE, and I would like to take advantage of design patterns such as Model view controller and model view view-model.
However, there doesn't seem to be much on the web about the best practices for doing this in pascal. Most of the examples that I can find are in C# and some of the language features are not present in pascal, which means I may have to find ways to implement those features.
I'm trying to adapt code from this article here
I'll list the issues that I'm facing
- Nullable types
Pascal does not have nullable types as C# does so I have created my own.
TNullable<T> = record
strict private
fHasValue : boolean;
fValue : T;
function GetValue:T;
procedure SetValue(newValue : T);
public
property HasValue : boolean read fHasValue;
property Value : T read GetValue write SetValue;
procedure SetToNull;
end;
in the implementation section
function TNullable<T>.GetValue:T;
begin
if fHasValue then
begin
Result := fValue;
end
else raise Exception.Create('Value Not Set');
end;
procedure TNullable<T>.SetValue(newValue : T);
begin
fValue := newValue;
fHasValue := true;
end;
procedure TNullable<T>.SetToNull;
begin
fHasValue := false;
end;
- Get/Set for properties
Now that I have a nullable type I can create nullable properties
However it comes with some code smells
for example if i create
TFoo = class
private
function GetBar:TNullable<Integer>;
procedure SetBar(x:TNullable<Integer>);
public
property Bar : TNullable<Integer> read GetBar write SetBar;
in the implementation section
function TFoo.GetBar:TNullable<Integer>;
begin
if **valueExists** then
begin
Result.Value := **the value**
end else
begin
Result.SetToNull;
end;
end;
procedure TFoo.SetBar(x:TNullable<Integer>);
begin
if X.hasValue then
begin
//Store/show value here
end else
begin
//handle null assignment here
end;
end;
This is fine but when it comes to use these properties I can't just use
myFoo.Bar.Value := 1;
I have to use
var
myBar : TNullable<Integer>;
begin
myBar.Value := 1;
myFoo.Bar := myBar;
end;
Which is a bit messier. I suppose there may be nothing I can do about this.
- Circular References
I like to separate classes into different units.
ie:
keeping the user interface separate from the control logic and the model and data logic layer.
I can have a situation where 2 classes can reference each other. While this is a situation that for the most part I would like to avoid, there are occasions where this is needed.
for example
unit u_A;
interface
uses
u_B
;
type
TA = class
public
Foo : TB;
end;
implementation
end;
and another unit
unit u_B;
interface
uses
u_A
;
type
TB = class
public
Foo : TA;
end;
implementation
end;
This code is broken because the two classes include each other and this can not be done in pascal. This is not such a problem in C#. Solutions that I can think of: 1. include both classes in the same unit, although this is a problem if I do not think this suits the design. 2. Create another parent interface for B and inherit B from that, then this gets around it. Although this is messy for such a simple task.
- Static classes
There aren't any static classes in Delphi, these are useful for control classes.
- Best Container classes to use in Delphi
I'm currently using TList and TObjectList in Generics.Collections
They were introduced in Delphi XE I hope these are the best to use since delphi 7 didn't seem to have any good options.
I'm still thinking about event handlers and any issues that may arise there. Perhaps there are some other issues that I have not thought of yet.
Thanks for any advice.
Best Answer
You should look into Spring4D as it already contains nullable types (similar implementation as yours with a little extra operator overloading) and way more powerful collection types than those in the RTL. They are also interfaced based which is very handy because you don't have to worry about lifetime management especially when passing them around.
For cross referencing problems I am suggesting coding against interfaces and use these as reference in another implementation rather than 2 implementations knowing each other.
As for the MVVM part you might look into DSharp which has a first version of a Caliburn Micro port for Delphi. It is very early stage and hardly documented but you might get some ideas how to achieve MVVM in Delphi using loosely coupled GUI and business logic connected with data bindings. The Blaise Pascal magazine had two articles about it if you are more interested.
P.S. I guess you mean you are using XE6 as that is the latest version.