我对IoC / DI还是很陌生,我正试图了解如何/应该在Spring4d中使用Delphi TForm。
我提供了一个示例,说明了我要清除的内容(主要是创建表单的TestIt过程)。由于TForm没有引用计数接口,因此容器可能无法使用它来创建它。
我已经包括了整个测试单元,以便可以就我是否也了解在这种环境中使用MVP进行评论。
感觉应该有一种更干净的方法来创建lPresenter,而不必手动创建TForm并将其注入到演示者中,然后必须将演示者注入到视图中。
我看到另一篇文章提到了实现TInterfacedObject的引用计数方法来实现引用计数,但这似乎无济于事。
也许更好的解决方案是使用DelegateTo并在其中创建具有所有属性注入的所有所需类,但这也让人感到不对。
Unit UI;
Interface
Uses
Vcl.Forms;
Procedure TestIt;
Implementation
Uses
Spring.Container,
WinApi.Windows,
Vcl.StdCtrls,
System.SysUtils,
System.Classes;
Type
IPresenter = Interface;
IModel = Interface(IInterface) ['{D1B8418C-4EC5-473D-9473-C385D6E2A12C}']
Function GetUsersName: String;
Procedure SetUsersName(aName: String);
Function GetAge: Integer;
Procedure SetAge(aAge: Integer);
Property UsersName: String Read GetUsersName Write SetUsersName;
Property Age: Integer Read GetAge Write SetAge;
Procedure FirstUser;
End;
IView = Interface(IInterface) ['{108E61F5-EDC8-48EC-9687-F6D38DA89BC4}']
Procedure Execute;
Function GetPresenter: IPresenter;
Procedure SetPresenter(aPresenter: IPresenter);
Function GetUsersName: String;
Procedure SetUsersName(aName: String);
Function GetAge: Integer;
Procedure SetAge(aAge: Integer);
Property Presenter: IPresenter Read GetPresenter Write SetPresenter;
Property UsersName: String Read GetUsersName Write SetUsersName;
Property Age: Integer Read GetAge Write SetAge;
End;
IPresenter = Interface(IInterface) ['{988D7D21-399A-45E6-B4E7-8E2670080385}']
Function Model: IModel;
Function GetView: IView;
Procedure SetView(aView: IView);
Procedure Execute;
Procedure LoadData;
Procedure SaveData;
Function DataValid: Boolean;
Property View: IView Read GetView Write SetView;
End;
TView = Class(TForm, IView)
Private
FPresenter: IPresenter;
FUsersName: TEdit;
FAge: TEdit;
FButton: TButton;
Procedure DoOk(aSender: TObject);
Public
Constructor Create; Reintroduce;
Procedure Execute;
Function GetPresenter: IPresenter;
Procedure SetPresenter(aPresenter: IPresenter);
Function GetUsersName: String;
Procedure SetUsersName(aName: String);
Function GetAge: Integer;
Procedure SetAge(aAge: Integer);
End;
TModel = Class(TInterfacedObject, IModel)
FUsersName: String;
FAge: Integer;
Public
Function GetUsersName: String;
Procedure SetUsersName(aName: String);
Function GetAge: Integer;
Procedure SetAge(aAge: Integer);
Procedure FirstUser;
End;
TPresenter = Class(TInterfacedObject, IPresenter)
FModel: IModel;
FView: IView;
Public
Constructor Create(aModel: IModel);
Function Model: IModel;
Function GetView: IView;
Procedure SetView(aView: IView);
Procedure Execute;
Procedure LoadData;
Procedure SaveData;
Function DataValid: Boolean;
End;
Procedure TestIt;
Var
lPresenter: IPresenter;
lView: IView;
Begin
GlobalContainer.RegisterType<IModel, TModel>;
GlobalContainer.RegisterType<IPresenter, TPresenter>;
GlobalContainer.Build;
lView := TView.Create;
lPresenter := GlobalContainer.Resolve<IPresenter>;
lPresenter.View := lView;
LView.Presenter := lPresenter;
lPresenter.Model.FirstUser;
lPresenter.Execute;
End;
{ TView }
Constructor TView.Create;
Begin
Inherited CreateNew(Nil);
FUsersName := TEdit.Create(Self);
FUsersName.Top := 20;
FUsersName.Left := 10;
InsertControl(FUsersName);
FAge := TEdit.Create(Self);
FAge.Top := 50;
FAge.Left := 10;
InsertControl(FAge);
FButton := TButton.Create(Self);
FButton.Top := 100;
FButton.Left := 10;
FButton.Caption := 'Ok';
InsertControl(FButton);
FButton.OnClick := DoOk;
End;
Procedure TView.DoOk(aSender: TObject);
Begin
If FPresenter.DataValid Then
Close
Else
MessageBeep(MB_ICONEXCLAMATION);
End;
Procedure TView.Execute;
Begin
ShowModal;
End;
Function TView.GetAge: Integer;
Begin
Result := StrToInt(FAge.Text);
End;
Function TView.GetUsersName: String;
Begin
Result := FUsersName.Text;
End;
Function TView.GetPresenter: IPresenter;
Begin
Result := FPresenter;
End;
Procedure TView.SetAge(aAge: Integer);
Begin
FAge.Text := IntToStr(aAge);
End;
Procedure TView.SetPresenter(aPresenter: IPresenter);
Begin
FPresenter := aPresenter;
End;
Procedure TView.SetUsersName(aName: String);
Begin
FUsersName.Text := aName;
End;
{ TModel }
Procedure TModel.FirstUser;
Begin
FUsersName := 'Peter Piper';
FAge := 25;
End;
Function TModel.GetAge: Integer;
Begin
Result := FAge;
End;
Function TModel.GetUsersName: String;
Begin
Result := FUsersName;
End;
Procedure TModel.SetAge(aAge: Integer);
Begin
FAge := aAge;
End;
Procedure TModel.SetUsersName(aName: String);
Begin
FUsersName := aName;
End;
{ TPresenter }
Constructor TPresenter.Create(aModel: IModel);
Begin
FModel := aModel;
End;
Function TPresenter.DataValid: Boolean;
Begin
Result := (FView.Age > 18) And (FView.Age < 100);
End;
Procedure TPresenter.Execute;
Begin
LoadData;
FView.Execute;
SaveData;
End;
Procedure TPresenter.LoadData;
Begin
FView.UsersName := FModel.UsersName;
FView.Age := FModel.Age;
End;
Function TPresenter.Model: IModel;
Begin
Result := FModel;
End;
Procedure TPresenter.SaveData;
Begin
FModel.UsersName := FView.UsersName;
FView.Age := FModel.Age;
End;
Procedure TPresenter.SetView(aView: IView);
Begin
FView := aView;
End;
Function TPresenter.GetView: IView;
Begin
Result := FView;
End;
end.