Naming.

Naming.

I am creating a command pattern hierarchy and one of the base classes is this:

TDatabaseBoundCommand = class( TCommandBase )
strict protected
function GetDataset : TD;virtual;abstract;

function CommandSucceded( out MsgText : String ): Boolean;virtual;abstract;
function Execute: TExecutionResult; override;
property Dataset : TD read GetDataset;
end;

For perspective, TCommandBase implements this interface:

TExecutionResult = ( erSuccess, erFail );
ICommand = interface
['{3A03CDCF-B9DB-46E7-8FBB-860DD909053B}']

function GetMessage: String;

function Execute : TExecutionResult;
property Message: String read GetMessage;
end;

In other words, it implements the message property and creates a virtual;abstract of the Execute method.

My issue is that right now my TDatabaseBoundCommand class depends on TDataSet but I realised I want to jeep it flexible enough that - for example - a RemObjects or kbmMW client layer can be implemented, thus I need to change the names in the class.

i have thought about, for instance, TRemoteCommand, but I don't really know if I like that, because a direct DB interface should also be available and I can't see how to make that work with this name,

What would you suggest?

Any ideas?

Comments

  1. Instead of making it generic like that, why not add an IDataSet interface, and make TDatabaseBoundCommand use delegation to an IDataSet implementation?

    ReplyDelete
  2. My goal is to defer as much as possible at the root. This is a research item that may come back as useful in the short/medium term.

    Because of how it was originally designed, nearly no code had a dependency on a dataset, apart from a "GetDataset" virtual abstract method and a Dataset property.

    Thus, I am not really disrupting anything, I simply changed my mind and decided that I can just as well do without at this level. I can always add a dataset restriction further down.

    I approach all generic classes this way: if there isn't a reason to make something constrained, I let it roam free. It's an accordion-like approach: I define as little as possible up the hierarchy and then specify things in ever so more detail as the layers get more specific. It's an approach that works well because at any given point you can make a different turn.

    ReplyDelete
  3. Maybe something like that. ..

    TdatasetFunc =reference to function  (const aDB:TdataSet; erMsg:string):boolean;

    TDataset_ex= classe helper for TDataset
    function Execute(aFunc: TdatasetFunc ;out msg:string): boolean;
    End;

    ReplyDelete
  4. Andrea Raimondi I guess my point was based on what you've shown I don't see the need for making it generic in the first place.

    ReplyDelete
  5. Asbjørn Heid It is if you're planning to have different ways to execute a single command. Say that for whatever reason you want to use ADO, ODAC, RemObjects and kbmMW: by making the "channel" generic you can quite easily and you don't have to regiment it in any specific way. Please have a look at this to see what I mean: pastebin.com - [Delphi] unit PIManager.Classes.Commands; interface uses PIManager.Interfaces.Core, - Pastebin.com

    ReplyDelete
  6. Andrea Raimondi I still don't see how delegation wouldn't be preferable. In your example, the Login command class doesn't depend on the channel at all? Not trying to be difficult here but I just don't see what generics brings to the party.

    ReplyDelete
  7. You're not difficult, I know I am weird :)

    This is one implemented command:
    pastebin.com - [Delphi] unit PIM.Persistence.Commands; interface uses PIManager.Ado.Commands, DMai - Pastebin.com

    The advantage is that between the previous and this one I can easily change direction and - for example - have the ODAC set or something entirely different such as REST calls. That's the advantage that generics bring over delegation: you can use everything without having to worry and at the same time it's more self-contained. It helps with debug and it's all there to be seen. Makes sense now?

    ReplyDelete

Post a Comment