Advertisement
Guest User

Untitled

a guest
Mar 31st, 2018
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 6.57 KB | None | 0 0
  1. unit PIManager.Classes.Commands;
  2.  
  3. interface
  4.  
  5. uses PIManager.Interfaces.Core, PIManager.Interfaces.Commands, PIManager.Classes.Core,
  6.      Generics.Collections, Generics.Defaults;
  7.  
  8. {
  9.   NOTES
  10.   -----
  11.   These commands work in a somewhat unusual way: the idea here is to defer the
  12.   actual implementation to an as late a time as possible, while instituting a
  13.   usable pattern that leaves a lot of freedom on how to do things.
  14.  
  15.   Because of this, we create a dependency on TDataSet, which we still need to
  16.   issue queries no matter what, then we override Execute and create a new method
  17.   called "CommandSucceded" which replaces the abstract execute. We do this
  18.   because then we can implement Execute and move a lot of logic there.
  19.   Finally, in the descendants we implement CommandSucceded and defer actual
  20.   implementation to a boolean method which is virtual and abstract. Again, this is
  21.   meant to split the actual workload across the classes so that we have a single
  22.   responsibility handled across the board. Plus, it is a repeatable pattern with no
  23.   downside because we aren't irregimenting in any meaningful way, therefore
  24.   each concrete implementation can then do things in the best possible way.
  25.  
  26.   Why do we want that, though? Imagine that you need to move this on to MySQL:
  27.   MySQL doesn't have good support for stored procedures, so you will probably
  28.   want a SELECT. However, MSSQL Server, for instance, does have that support and
  29.   therefore you may want to use a TAdoStoredProc! With this system, you're not
  30.   obliged to use a TAdoQuery, which you would if we had a method called - for instance -
  31.   GetLoginSQL. See the point I am making here?
  32.  
  33.   On the other hand, though, if you wanted to allow something such as RemObjects for
  34.   remote DB calls, all you need to do is to copy the same kind of scheme in a new
  35.   unit and the client won't really notice that behind the scenes we're doing anything
  36.   peculiar.
  37. }
  38.  
  39. Type
  40.  
  41.   TChannelBoundCommand<TChannel> = class( TCommandBase )
  42.   strict protected
  43.     function GetChannel : TChannel;virtual;abstract;
  44.  
  45.     function CommandSucceded( out MsgText : String ): Boolean;virtual;abstract;
  46.     function Execute: TExecutionResult; override;
  47.     property Channel : TChannel read GetChannel;
  48.   end;
  49.  
  50.   TLoginCommand<TChannel> = class( TChannelBoundCommand<TChannel>,ILoginCommand )
  51.   private
  52.     FLoggedInToken: String;
  53.     FUserName : String;
  54.     FPassword : String;
  55.   strict protected
  56.     function Login : Boolean;virtual;abstract;
  57.     function CommandSucceded( out MsgText: String ): Boolean;override;
  58.     function GetLoggedInToken: string;
  59.     procedure SetPassword(Value: string);
  60.     procedure SetUserName(Value: string);
  61.  
  62.     property LoggedInToken: String read GetLoggedInToken write FLoggedInToken;
  63.     property UserName : String read FUserName write SetUserName;
  64.     property Password : String read FPassword write SetPassword;
  65.   end;
  66.  
  67.   TUserCommand<TUser;TChannel> = class( TChannelBoundCommand<TChannel> )
  68.   strict private
  69.     FUser : TUser;
  70.   strict protected
  71.      procedure SetUser( Value: TUser );virtual;abstract;
  72.  
  73.      function GetUserName : String;virtual;abstract;
  74.  
  75.      property User: TUser read FUser write SetUser;
  76.   end;
  77.  
  78.   TNewUserCommand<TUser;TChannel> = class( TUserCommand<TUser,TChannel>,INewUserCommand<TUser> )
  79.   strict protected
  80.  
  81.     function InsertUser : Boolean;virtual;abstract;
  82.     function CommandSucceded( out MsgText : String ): Boolean;override;
  83.   end;
  84.  
  85.   TLoadContactsForUser<TContact, TUser,TChannel> = class( TUserCommand<TUser,TChannel>, ILoadContactsForUser<TContact,TUser> )
  86.   strict private
  87.     FContacts: TArray<TContact>;
  88.     FContactsAsList : TList<TContact>;
  89.   strict protected
  90.     function GetContacts: TArray<TContact>;
  91.     function LoadContacts: Boolean;virtual;abstract;
  92.     procedure AddContactToList( AContact: TContact );
  93.     function CommandSucceded( out OutMessage: String ): Boolean;override;
  94.   public
  95.     constructor Create;override;
  96.     destructor Destroy;override;
  97.   end;
  98.  
  99. implementation
  100.  
  101. uses SysUtils;
  102.  
  103. { TLoginCommand<TD> }
  104.  
  105. function TLoginCommand<TChannel>.CommandSucceded(out MsgText: String): Boolean;
  106. begin
  107.   MsgText := '';
  108.   Result := Login;
  109.   if Result then
  110.     MsgText := 'Login succeeded for user '+UserName
  111.   else
  112.     MsgText := 'Login failed for user '+UserName;
  113. end;
  114.  
  115. function TLoginCommand<TChannel>.GetLoggedInToken: string;
  116. begin
  117.   Result := FLoggedInToken;
  118. end;
  119.  
  120. procedure TLoginCommand<TChannel>.SetPassword(Value: string);
  121. begin
  122.   FPassword := Value;
  123. end;
  124.  
  125. procedure TLoginCommand<TChannel>.SetUserName(Value: string);
  126. begin
  127.   FUserName := Value;
  128. end;
  129.  
  130. { TDatabaseBoundCommand<TD> }
  131.  
  132. function TChannelBoundCommand<TChannel>.Execute: TExecutionResult;
  133. var OutMessage: String;
  134. begin
  135.   Result := erFail;
  136.   try
  137.     if CommandSucceded( OutMessage ) then
  138.       Result := erSuccess;
  139.     Message := OutMessage;
  140.   except
  141.     on E: Exception do
  142.     begin
  143.       Message := 'Exception of type '+E.ClassName + ' raised with message: "'+E.Message+'"';
  144.     end;
  145.   end;
  146. end;
  147.  
  148. { TNewUserCommand<TUser, TD> }
  149.  
  150. function TNewUserCommand<TUser, TChannel>.CommandSucceded(
  151.   out MsgText: String): Boolean;
  152. begin
  153.   MsgText := '';
  154.   Result := InsertUser;
  155.   if Result then
  156.     MsgText := 'Insertion of user '+GetUserName+' succeded'
  157.   else
  158.     MsgText := 'There was a problem inserting the user '+GetUserName;
  159. end;
  160.  
  161. { TLoadContactsForUser<TContact, TUser, TChannel> }
  162.  
  163. procedure TLoadContactsForUser<TContact, TUser, TChannel>.AddContactToList(
  164.   AContact: TContact);
  165. begin
  166.   FContactsAsList.Add( AContact );
  167. end;
  168.  
  169. function TLoadContactsForUser<TContact, TUser, TChannel>.CommandSucceded(
  170.   out OutMessage: String): Boolean;
  171. begin
  172.   try
  173.     Result := LoadContacts;
  174.     if Result then
  175.     begin
  176.       FContacts := FContactsAsList.ToArray;
  177.       OutMessage := 'Loaded '+IntToStr( FContactsAsList.Count )+ ' contacts';
  178.     end
  179.     else begin
  180.       OutMessage := 'Could not load contacts for user '+GetUserName;
  181.     end;
  182.   except
  183.     on E: Exception do
  184.     begin
  185.       OutMessage := 'Exception of type '+E.ClassName +' was raised with message: "'+E.Message+'"';
  186.       Result := False;
  187.     end;
  188.   end;
  189. end;
  190.  
  191. constructor TLoadContactsForUser<TContact, TUser, TChannel>.Create;
  192. begin
  193.   inherited;
  194.   FContactsAsList := TList<TContact>.Create;
  195. end;
  196.  
  197. destructor TLoadContactsForUser<TContact, TUser, TChannel>.Destroy;
  198. begin
  199.   FContactsAsList.Free;
  200.   SetLength( FContacts,0 );
  201.   inherited;
  202. end;
  203.  
  204. function TLoadContactsForUser<TContact, TUser, TChannel>.GetContacts: TArray<TContact>;
  205. begin
  206.   Result := FContacts;
  207. end;
  208.  
  209. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement