Jump to content

MVC pattern in UniGUI vs traditional coding to form


elGringo

Recommended Posts

Hi, dear all. Learning ASP MVC. Question is in implementing MVC pattern in UniGUI framework.

I want to understand,starting this discussion

  -is there any sense of implementing of this pattern in UNIGUI, cause main plus of MVC is better structure of app and better testing

   -what are concrete ways of implementations,  maybe simple examples...

  -is someone tried? Any effort? Any experience? Share please your thoughts and practices you faced with.

 

As for my thoughts

  

  Models code could be in MainModule

  Views are forms

   Controllers are separate units...

 

On the other hand - traditional Delphi style codeing to form when everything is coded in form and that is bad practice, because it is good on the start, good as RAD approach, but after dozens of units it become to be a mess, don't you reckon like this?

 

That is the starting point...

Link to comment
Share on other sites

Hi guys,

 

The theory is beautiful, but practical results are more important.

 

The MVC pattern intends to achieve a clear separation between the user interface and the business logic.

This goal becomes paramount when you need to share the business logic when you target several platforms for your user interface.

In uniGUI you already have two targets: desktop and mobile (touch).

 

Delphi already provides tools for achieving that separation without having to add unnecessary code.

Basically, any Delphi form can be bound to objects in a data module using event handlers and actions.

Just by using these tools, you won't need anything else for achieving the separation.

 

The Small Hybrid App in Demos\Touch uses this approach.

 

I hope this helps...

Link to comment
Share on other sites

Yes! That is the thoughts i waited for ! Delphi has its unique architecture.

Form itself has dfm and pas parts that are bounded, the engeneers of Delphi tried to give us more speed in developing soft! 

So on start we have already structure we can use. Actions and events (procedures and functions of object) are those tools to connect everything to everything.

Other question - is how convenient is it? How easy to read and understand this code to new person of project?

 

Experiment shows all! Lets write simple app that just will concat 2 Uniedits here in different patterns and together understand which approach is better!

 

Ok, having

    eLeft: TUniEdit;
    eRight: TUniEdit;
    lResult: TUniLabel;
    bConcat: TUniBitBtn;

1 st approach is Delphi approach - concat directly using form vars

procedure TMainForm.bConcatClick(Sender: TObject);
begin
lResult.Caption:=eLeft.text+eRight.Text;
end;

2d approach is MVC

 

 creating models with sync to main

unit uModel;

interface

uses
  SysUtils, Classes;

type
  TModel = class(TDataModule)
  private
    FLeft: string;
    FRight: string;
    FResult: string;
    procedure SetLeft(const Value: string);
    procedure SetRight(const Value: string);
    procedure SetResult(const Value: string);
    { Private declarations }

  public
    { Public declarations }
    property Left:string read FLeft write SetLeft;
    property Right:string read FRight write SetRight;
    property Result:string read FResult write SetResult;
  end;

function Model: TModel;

implementation

{$R *.dfm}

uses
  UniGUIVars, uniGUIMainModule, MainModule,Main;

function Model: TModel;
begin
  Result := TModel(UniMainModule.GetModuleInstance(TModel));
end;

{ TModel }

procedure TModel.SetLeft(const Value: string);
begin
  if (Value<>FLeft) then
  begin
  FLeft := Value;
  MainForm.eLeft.Text:=Value;
  end;
end;

procedure TModel.SetResult(const Value: string);
begin
  if (Value<>FLeft) then
  begin
  FResult := Value;
  MainForm.lResult.Caption:=Value;
  end;
end;

procedure TModel.SetRight(const Value: string);
begin
if (Value<>FRight) then
  begin
  FRight := Value;
  MainForm.eRight.Text:=Value;
  end;
end;

initialization
  RegisterModuleClass(TModel);

end.

Model is created in UniMainModule

procedure TUniMainModule.UniGUIMainModuleCreate(Sender: TObject);
begin
FModel:=TModel.Create(UniApplication);
end;

Sync View to model

procedure TMainForm.eLeftChange(Sender: TObject);
begin
UniMainModule.Model.Left:=eLeft.Text;
end;

procedure TMainForm.eRightChange(Sender: TObject);
begin
UniMainModule.Model.Right:=eRight.Text;
end;

Controller method

procedure TController.Concat;
begin
with UniMainModule do begin
Model.Result:=Model.Left+Model.Right;
end;

full Controller

unit uController;

interface

uses
  SysUtils, Classes;

type
  TController = class(TDataModule)
  private
    { Private declarations }
  public
    { Public declarations }
    procedure Concat();
  end;

function Controller: TController;

implementation

{$R *.dfm}

uses
  UniGUIVars, uniGUIMainModule, MainModule;

function Controller: TController;
begin
  Result := TController(UniMainModule.GetModuleInstance(TController));
end;

{ TController }

procedure TController.Concat;
begin
with UniMainModule do begin
Model.Result:=Model.Left+Model.Right;
end;

end;

initialization
  RegisterModuleClass(TController);

end.

instance of Controller called directly as UniGUI allows it

 

 

use of MVC approach

procedure TMainForm.bConcatClick(Sender: TObject);
begin
UniMainModule.Controller.Concat();
end;

My conclusions

 -mvc is more difficult in realization

 -delphi already has its unique structure and there is unique Delphi pattern, no needed to import MVC, but possible

 -on that small example I easily used already done infrastructure of Delphi components and to concat i just needed to write one string!

 -as for mvc approach i needed to do a lot of additional work, create new structure in model, sync it to view and view to it, and this sync is not full...

 

in ASP MVC for example not other structure then MVC, so if not use MVC unclear how to organize coding, so in ASP MVC it is necessary to use mvc Approach, in Delphi we can choose, and it is advantage...

 

Maybe in big projects mvc is better, but small test shows lots of additional work...

Link to comment
Share on other sites

Besides!

Firstly I wanted to show code of simple calc like this below in 2 patterns, but I don't even want to think how complicated it to transfer in MVC pattern... 

unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uniGUITypes, uniGUIAbstractClasses, uniGUIClasses, uniGUIRegClasses,
  uniGUIForm, uniEdit, uniGUIBaseClasses, uniButton, uniBitBtn, uniLabel;

type
  TMainForm = class(TUniForm)
    b8: TUniBitBtn;
    b9: TUniBitBtn;
    b4: TUniBitBtn;
    b5: TUniBitBtn;
    b6: TUniBitBtn;
    bOne: TUniBitBtn;
    b2: TUniBitBtn;
    b3: TUniBitBtn;
    eResult: TUniEdit;
    UniBitBtn10: TUniBitBtn;
    bEqual: TUniBitBtn;
    bDivide: TUniBitBtn;
    bMultiply: TUniBitBtn;
    bMinus: TUniBitBtn;
    bPlus: TUniBitBtn;
    bCE: TUniBitBtn;
    b7: TUniBitBtn;
    unilabel: TUniLabel;
    procedure UniFormCreate(Sender: TObject);
    procedure digitClick(Sender: TObject);
    procedure signClick(Sender: TObject);
    procedure bEqualClick(Sender: TObject);
    procedure bCEClick(Sender: TObject);
  private
    { Private declarations }
    faIsEmpty: Boolean;
    fbIsEmpty: Boolean;
    fcIsEmpty: Boolean;
    fdIsEmpty: Boolean;
    fIsSignClickedBefore: Boolean;
    fIsDigitClicked: Boolean;
    fa, fb, fc: real;
    fd: char;
    foperators: set of Char;
    procedure nullAll;
  public
    { Public declarations }
  end;

function MainForm: TMainForm;

implementation

{$R *.dfm}

uses
  uniGUIVars, MainModule, uniGUIApplication, System.Generics.Collections;

function MainForm: TMainForm;
begin
  Result := TMainForm(UniMainModule.GetFormInstance(TMainForm));
end;

procedure TMainForm.bCEClick(Sender: TObject);
begin
  nullAll();
end;

procedure TMainForm.bEqualClick(Sender: TObject);
begin
  case fd of
    '-':
      fc := fa - fb;
    '+':
      fc := fa + fb;
    '*':
      fc := fa * fb;
    '/':
      fc := fa / fb;
  end;
  fa := fc;
  fbIsEmpty := True;
  eResult.Text := FloatToStr(fc);
end;

procedure TMainForm.nullAll;
begin
  fa := 0.00;
  fb := 0.00;
  fc := 0.00;
  unilabel.Caption := '';
  faIsEmpty := true;
  fbIsEmpty := true;
  fcIsEmpty := true;
  fdIsEmpty := true;
  foperators := ['+', '-', '*', '/'];
  unilabel.Caption := '';
  eResult.Text := '';
end;

procedure TMainForm.digitClick(Sender: TObject);
begin
  fIsSignClickedBefore := false;
  fIsDigitClicked := True;
  if faIsEmpty then
  begin
    fa := strToFloat((Sender as TUniBitbtn).Caption);
    faIsEmpty := false;
  end
  else
  begin
    fb := strToFloat((Sender as TUniBitbtn).Caption);
    fbIsEmpty := False;
  end;
  unilabel.Caption := unilabel.Caption + (Sender as TUniBitbtn).Caption;
end;

procedure TMainForm.signClick(Sender: TObject);
var
  s: string;
  lastSymbol:char;
begin
  fdIsEmpty := false;
  if fIsSignClickedBefore then
  begin
    s := unilabel.Caption;
    lastSymbol:=s[Length(s)];
    if ((s[Length(s)] in foperators) and ((lastSymbol <> (Sender as TUniBitbtn).Caption))) then
    begin
      delete(s, length(s), 1);
      fdIsEmpty := true;
      unilabel.Caption := s;
      //fIsSignClickedBefore := false;
    end
    else if (s[Length(s)] = (Sender as TUniBitbtn).Caption) then
      exit;
  end;

  unilabel.Caption := unilabel.Caption + (Sender as TUniBitbtn).Caption;
  s := (Sender as TUniBitBtn).Caption;
  fd := s[Low(s)];
  if fdIsEmpty then
    exit;

  if not fIsDigitClicked and fIsSignClickedBefore then
    exit;

  fIsSignClickedBefore := true;

  if (not faIsEmpty) and (not fbIsEmpty) then
  begin
    case fd of
      '-':
        fc := fa - fb;
      '+':
        fc := fa + fb;
      '*':
        fc := fa * fb;
      '/':
        fc := fa / fb;
    end;
    fa := fc;
    eResult.Text := FloatToStr(fc);
    fIsDigitClicked := false;
  end;
end;

procedure TMainForm.UniFormCreate(Sender: TObject);
begin
  nullAll();
end;


initialization
  RegisterAppFormClass(TMainForm);

end.

Link to comment
Share on other sites

Thanks, rgreat! Clean code is result of experience imho. I code for 3 years, and code of my first year is unclean for me )))

In langs like php it is unclear how to organize code, so MVC is applied as mostly simple and convenient.

MVC gives fixed structure but it also takes time to support this structure. I mean - sometimes it is easier to call some small method from view, but structure says - write methods in controller, bind it to view. And you have to.

My regards to all readers and writers of topic!

Don't hesistate to share your thoughts.

Link to comment
Share on other sites

Hi,

Thanks to all who had participate to this topic. Very interesting. So maybe as conclusion we could say:

Project: Complex, quality is the top priority (medicinal software, rocket steering ): Use MVC approach. Write test code for automatic test scenes ( "continous integration" ). If you are more then one developer team working on the same project, then this approach would recommended.

Project: Not very complicated, quality is important but not a killer argument: Use standard "Delphi" approach. 

 

OK?

Link to comment
Share on other sites

Hello,

 

For MVC the benefits would be great if the code is autogenerated instead of hand coded. Too much efforts needed to code by hand.

But code/form generator would benefit all kind of programming paradigm. Even more benefits with the Delphi RAD way.

Imagine that when we create a database application, we define datasets (sql, which fields shown in grid, which fields included in insert & edit, field labels, default values, etc) and a few clicks later, for each dataset it will autogenerate *.dfm and *.pas of:
- a datamodule that contains the dataset
- a form with dbgrid to browse, filter and search the dataset
- a form to do insert & edit the dataset

and those forms are ready to use and customize.

This would save time greatly :D

Link to comment
Share on other sites

"Too much efforts needed to code by hand"

In delphi Yes for the moment unfortunately, but thanks, delphi has its own structure, that can be used easily

 

"Imagine that when we create a database application, we define datasets "

such approach done in ASP MVC when there is DB context from Entity Framework which is alredy automates most of work...

 

Besides - do you use db aware or live bindings designer?

Link to comment
Share on other sites

  • 11 months later...

A big reason to prefer more decoupled approaches such as MVC, MVP, MVVM, MV* is testability.  If all your logic is inside event handlers then typically it's quite hard to properly test and not possible to test entirely in isolation.  This may not be a show stopping problem but it is a consideration at least.  (Also see for example the "Humble Dialog" pattern and "Humble View".)

  • Upvote 1
Link to comment
Share on other sites

1 hour ago, wprins said:

A big reason to prefer more decoupled approaches such as MVC, MVP, MVVM, MV* is testability.  If all your logic is inside event handlers then typically it's quite hard to properly test and not possible to test entirely in isolation.  This may not be a show stopping problem but it is a consideration at least.  (Also see for example the "Humble Dialog" pattern and "Humble View".)

Absolutely!

Link to comment
Share on other sites

  • 4 weeks later...

Hi, I'm sorry for be late, I hope this subject still be worm. I had published some time ago a simple post about MVVM in UNIGUI using KNOCKOFF (from Stefan Glienke) adapted to UNIGUI. Here is the link.

Post´s Link

Since that time, I have been working with this pattern in UNIGUI with TMS Aurelius, and yes, code is cleaner. The limitation I found on this approach is the creation of an adapter for each component. But it is working.

 

I hope this could help.

 

Regards

Link to comment
Share on other sites

  • 3 years later...
On 11/5/2018 at 10:18 AM, Bresler said:

Hi, I'm sorry for be late, I hope this subject still be worm. I had published some time ago a simple post about MVVM in UNIGUI using KNOCKOFF (from Stefan Glienke) adapted to UNIGUI. Here is the link.

Post´s Link

Since that time, I have been working with this pattern in UNIGUI with TMS Aurelius, and yes, code is cleaner. The limitation I found on this approach is the creation of an adapter for each component. But it is working.

 

I hope this could help.

 

Regards

Do you have any update on this simple MVVM framework with TMS Aruelius?  I am very interested. Thank you. @Bresler

Link to comment
Share on other sites

Hello,

These learned words "Paradigm, MVC PATERN, MVVM, ..."  sound good to the ear, 

But why doing complex, when things could be done easyer ?

Delphi is OOP. You can write very clean code with this technic. Just separate your Gui interface from your logic.

1. Design what you want on your uniFrame.

2. Use Object on your events

3. Create a Class on a uniDataModule and describe as well as possible your fields / methods.

That what i am doing.

I confirm : this makes things a lot easier, especially when reading code later.

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...