Hello!

Hello!

So, I understand the concept of having interfaces only in your programs and I even quite agree with it. I agree with the testability of things.

However, one thing is to understand and agree to the concept and another thing is applying the technique.

That's where I am stuck.

I don't know if I am just too used to classes, that may well be, but I need a bit of help.

So these are my details.

I have an interface:

IContact = interface
  ['{79D205DC-FC0E-45F0-A388-56CBBFBF204A}']
    procedure SetFirstName(const Value: string);
    function GetFirstName: string;
    procedure SetLastName(const Value: string);
    function GetLastName: string;
    procedure SetBirthDate(const Value: TDateTime);
    function GetBirthDate: TDateTime;

    property BirthDate: TDateTime read GetBirthDate write SetBirthDate;
    property FirstName: string read GetFirstName write SetFirstName;
    property LastName: string read GetLastName write SetLastName;
  end;

Now I have a new class (I will extract its interface later, I need to implement its methods first though):

TContactList = class
  private
    FList: IList;
    procedure SetList(const Value: IList);
    function GetList: IList;
  public
    constructor Create;
    procedure Add( AContact : IContact );
    procedure Delete( AContact: IContact );
    procedure SortByLastName;
    property List : IList< IContact > read GetList write SetList;
  end;

Now, my problem is with SortByLastName.

The constructor for the class is this:

constructor TContactList.Create;
begin
  inherited Create;
  FList := TCollections.CreateList;
end;

I am not sure how I should be implementing "SortByLastName" (which is a very basic functionality for a contact list application).

Any suggestions?

Please note I am making no assumptions as to what the right way to do this is, thus I am hoping someone like Stefan Glienke  will chime in and help a bit :)

Kind Regards,

A

Comments

  1. When talking about coding against interfaces (or better abstractions) we are talking about so called service classes (or injectables as Misko Hevery calls them) - please read his article here: http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/

    It is very important to differ between these two types of classes:
    - newables, PODO, data objects
    - injectables, service classes

    You only want to make interfaces for the injectables because these are the things you want to test and possibly mock. The newables are also those classes (hence the name Misko chose) that you can just create in your program and usually don't obtain through a container (or only through a factory which you registered which you obtain from a container).

    ReplyDelete
  2. Ok so now we're saying: not everything has to be an interface, but only what is injectable.
    Is that correct?

    ReplyDelete
  3. Andrea Raimondi Correct. Some of the DI examples since they are so simple might give the impression that you should do that with newables also (like the TKnight example Nick gave)

    The coding against abstractions should not be a dogma that you follow although not understanding but a way to create testable code. In in your example of a contact there is nothing to test because it does not have any function. Thus you never need to mock it and thus you don't need to code against an abstraction here.

    ReplyDelete
  4. Another thing about your original code (which is not related to your question but which I like to point out). You should go with an IList directly and implement the sorting kind over the comparer that you pass into the Sort method.

    ReplyDelete
  5. Ok then but bear with me for a minute, will you :)

    I am a bit stubborn and I like to explore my way around :)

    Let's try and do it with newables as well :)

    How would you implement SortByLastName?

    Btw, my newable is created via a function that takes a TDataset parameter (that was the closest abstraction I could find).

    ReplyDelete
  6. See my previous comment. Why? Think about some added requirement. Someone says: I want to sort them by BirthDate. Then a week later we add some more properties to TContact and someone says. I want to get them ordered by City,Street and Firstname. And every time you add another SortByXXX method to your TContactList.

    ReplyDelete
  7. You have to do that even if you have it set free.

    Either that, or I am missing some crucial bit here.

    A

    ReplyDelete
  8. You only have to write a comparison for the particular sorting you want to perform and pass that to the Sort method but not implement any method on the list for every sorting you want to perform. Plus you don't have an extra list type with all these SortByXX methods on which you are creating a dependency on.

    ReplyDelete
  9. I was thinking about it and I was coming to the conclusion that, really, that list has to be hidden - since it's my concrete implementation :)

    My final scope is so much bigger than this example, but I really need to lay a good foundation to this.

    A

    ReplyDelete
  10. Unless I know a plausible reason (some legacy code maybe) I am going to argue that you don't need to wrap an IList and make your own implementation around it. If at all make your own implementation of IList based on TListBase or TList.

    ReplyDelete
  11. There's a basic misunderstanding here: I am not trying to make my own implementation of the list :)
    What I am trying to do is to encapsulate the list into my class. It's the same concept as having a specialised TObjectList that lives inside your class.

    A

    ReplyDelete
  12. Well then - don't see the problem:

    procedure SortByLastname;
    begin
      FList.Sort(
        function(const left, right: TCustomer): Integer
        begin
          Result := CompareText(left.Lastname, right.Lastname);
        end); 
    end;

    ReplyDelete
  13. It works, but I am not sure how - I thought it was expecting an interface...

    ReplyDelete
  14. You either pass IComparer or directly a TComparison (look them up in Collections.Defaults.pas)

    ReplyDelete

Post a Comment