Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- unit PIManager.Classes.Commands;
- interface
- uses PIManager.Interfaces.Core, PIManager.Interfaces.Commands, PIManager.Classes.Core,
- Generics.Collections, Generics.Defaults;
- {
- NOTES
- -----
- These commands work in a somewhat unusual way: the idea here is to defer the
- actual implementation to an as late a time as possible, while instituting a
- usable pattern that leaves a lot of freedom on how to do things.
- Because of this, we create a dependency on TDataSet, which we still need to
- issue queries no matter what, then we override Execute and create a new method
- called "CommandSucceded" which replaces the abstract execute. We do this
- because then we can implement Execute and move a lot of logic there.
- Finally, in the descendants we implement CommandSucceded and defer actual
- implementation to a boolean method which is virtual and abstract. Again, this is
- meant to split the actual workload across the classes so that we have a single
- responsibility handled across the board. Plus, it is a repeatable pattern with no
- downside because we aren't irregimenting in any meaningful way, therefore
- each concrete implementation can then do things in the best possible way.
- Why do we want that, though? Imagine that you need to move this on to MySQL:
- MySQL doesn't have good support for stored procedures, so you will probably
- want a SELECT. However, MSSQL Server, for instance, does have that support and
- therefore you may want to use a TAdoStoredProc! With this system, you're not
- obliged to use a TAdoQuery, which you would if we had a method called - for instance -
- GetLoginSQL. See the point I am making here?
- On the other hand, though, if you wanted to allow something such as RemObjects for
- remote DB calls, all you need to do is to copy the same kind of scheme in a new
- unit and the client won't really notice that behind the scenes we're doing anything
- peculiar.
- }
- Type
- TChannelBoundCommand<TChannel> = class( TCommandBase )
- strict protected
- function GetChannel : TChannel;virtual;abstract;
- function CommandSucceded( out MsgText : String ): Boolean;virtual;abstract;
- function Execute: TExecutionResult; override;
- property Channel : TChannel read GetChannel;
- end;
- TLoginCommand<TChannel> = class( TChannelBoundCommand<TChannel>,ILoginCommand )
- private
- FLoggedInToken: String;
- FUserName : String;
- FPassword : String;
- strict protected
- function Login : Boolean;virtual;abstract;
- function CommandSucceded( out MsgText: String ): Boolean;override;
- function GetLoggedInToken: string;
- procedure SetPassword(Value: string);
- procedure SetUserName(Value: string);
- property LoggedInToken: String read GetLoggedInToken write FLoggedInToken;
- property UserName : String read FUserName write SetUserName;
- property Password : String read FPassword write SetPassword;
- end;
- TUserCommand<TUser;TChannel> = class( TChannelBoundCommand<TChannel> )
- strict private
- FUser : TUser;
- strict protected
- procedure SetUser( Value: TUser );virtual;abstract;
- function GetUserName : String;virtual;abstract;
- property User: TUser read FUser write SetUser;
- end;
- TNewUserCommand<TUser;TChannel> = class( TUserCommand<TUser,TChannel>,INewUserCommand<TUser> )
- strict protected
- function InsertUser : Boolean;virtual;abstract;
- function CommandSucceded( out MsgText : String ): Boolean;override;
- end;
- TLoadContactsForUser<TContact, TUser,TChannel> = class( TUserCommand<TUser,TChannel>, ILoadContactsForUser<TContact,TUser> )
- strict private
- FContacts: TArray<TContact>;
- FContactsAsList : TList<TContact>;
- strict protected
- function GetContacts: TArray<TContact>;
- function LoadContacts: Boolean;virtual;abstract;
- procedure AddContactToList( AContact: TContact );
- function CommandSucceded( out OutMessage: String ): Boolean;override;
- public
- constructor Create;override;
- destructor Destroy;override;
- end;
- implementation
- uses SysUtils;
- { TLoginCommand<TD> }
- function TLoginCommand<TChannel>.CommandSucceded(out MsgText: String): Boolean;
- begin
- MsgText := '';
- Result := Login;
- if Result then
- MsgText := 'Login succeeded for user '+UserName
- else
- MsgText := 'Login failed for user '+UserName;
- end;
- function TLoginCommand<TChannel>.GetLoggedInToken: string;
- begin
- Result := FLoggedInToken;
- end;
- procedure TLoginCommand<TChannel>.SetPassword(Value: string);
- begin
- FPassword := Value;
- end;
- procedure TLoginCommand<TChannel>.SetUserName(Value: string);
- begin
- FUserName := Value;
- end;
- { TDatabaseBoundCommand<TD> }
- function TChannelBoundCommand<TChannel>.Execute: TExecutionResult;
- var OutMessage: String;
- begin
- Result := erFail;
- try
- if CommandSucceded( OutMessage ) then
- Result := erSuccess;
- Message := OutMessage;
- except
- on E: Exception do
- begin
- Message := 'Exception of type '+E.ClassName + ' raised with message: "'+E.Message+'"';
- end;
- end;
- end;
- { TNewUserCommand<TUser, TD> }
- function TNewUserCommand<TUser, TChannel>.CommandSucceded(
- out MsgText: String): Boolean;
- begin
- MsgText := '';
- Result := InsertUser;
- if Result then
- MsgText := 'Insertion of user '+GetUserName+' succeded'
- else
- MsgText := 'There was a problem inserting the user '+GetUserName;
- end;
- { TLoadContactsForUser<TContact, TUser, TChannel> }
- procedure TLoadContactsForUser<TContact, TUser, TChannel>.AddContactToList(
- AContact: TContact);
- begin
- FContactsAsList.Add( AContact );
- end;
- function TLoadContactsForUser<TContact, TUser, TChannel>.CommandSucceded(
- out OutMessage: String): Boolean;
- begin
- try
- Result := LoadContacts;
- if Result then
- begin
- FContacts := FContactsAsList.ToArray;
- OutMessage := 'Loaded '+IntToStr( FContactsAsList.Count )+ ' contacts';
- end
- else begin
- OutMessage := 'Could not load contacts for user '+GetUserName;
- end;
- except
- on E: Exception do
- begin
- OutMessage := 'Exception of type '+E.ClassName +' was raised with message: "'+E.Message+'"';
- Result := False;
- end;
- end;
- end;
- constructor TLoadContactsForUser<TContact, TUser, TChannel>.Create;
- begin
- inherited;
- FContactsAsList := TList<TContact>.Create;
- end;
- destructor TLoadContactsForUser<TContact, TUser, TChannel>.Destroy;
- begin
- FContactsAsList.Free;
- SetLength( FContacts,0 );
- inherited;
- end;
- function TLoadContactsForUser<TContact, TUser, TChannel>.GetContacts: TArray<TContact>;
- begin
- Result := FContacts;
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement