Amazon.com Widgets Nick Hodges | A man's got to know his limitations

Calculating Pi

By Nick at August 10, 2011 02:36
Filed Under: Delphi

More Stuff I found on my Embarcadero Blog. I believe that my unusual use of the case statement caused a bit of a stir.  I still like using case in this way….


This was fun to write.  I read this interesting post on StackOverflow, which had an answer about asking interview questions, and this was the example he gave:

Given that Pi can be estimated using the function 4 * (1 - 1/3 + 1/5 - 1/7 + …) with more terms giving greater accuracy, write a function that calculates Pi to an accuracy of 5 decimal places.

Now, I don’t get to do much coding anymore, but hey, I’m not completely out of it, so I thought I’d try my hand at it. This is what I came up with:

function CalculatePi(aIterations: Cardinal): Extended;
var
  Counter: Cardinal;
  Denominator: integer;
begin
  Counter := 0;
  Denominator := 3;
  Result := 1;

  repeat
    case Odd(Counter) of
      True:  begin
               Result := Result + (1/Denominator);
             end;
      False: begin
               Result := Result - (1/Denominator);
             end;
    end;
    Inc(Counter);
    Denominator := Denominator + 2;
  until Counter >= aIterations ;

  Result := Result * 4;
end;

Now, again, I’m no Barry Kelly, and I’m sure that this could be optimized, but I was pretty pleased with that in a ‘that’s what I would have hacked out in an interview" kind of way.  :-)

The more iterations you pass in, the more precise it gets, obviously. I actually didn’t answer the full question (I skipped the precision part), but casual testing shows that about 10,000,000 iterations gets about 5 decimal points of accuracy. In fact, 10,000,000 iteration produces 3.14159275358978, which is pretty accurate.

Ten Things That Really Bug Me

By Nick at August 09, 2011 14:13
Filed Under: Software Development, General

I found this on my Embarcadero blog from 13 April 2009.  I wanted to preserve it here…


I was cleaning up my hard drive and I found lying around in an old HTML file.  The date on the file was from April of 2006, before I came to CodeGear.  I can’t remember if I ever put this up on a blog somewhere, but I thought it was a pretty good rant, so I’m posting it here. :-)

  1. Message boxes that ask a Yes/No question, but give you Ok/Cancel buttons. I mean, come on. If you are asking a "Yes or No" question, how tough is it to tell the dialog to have Yes and No buttons? Not tough at all, that’s how tough it is.
  2. Ok buttons that are enabled when a dialog is not properly filled in.   This is basic User Interface design. If pushing a button will result in an error message, don’t let the user push the button.
  3. Non-sizable dialogs.  Argh. This one drives me nuts. It’s especially galling when there’s a list box or something that is so small you feel like you are looking at it through a straw.
  4. Dialogs that don’t remember their size and position. Related to the previous item. Sometimes a dialog is too small, and when I size it, I want it to stay sized. Sometimes it blocks stuff I want to see. It should stay where I put it.
  5. Windows that insist on putting themselves in front when I am doing something else. This is absolutely, unequivocally the most irritating thing about Windows. I decide what I am looking at, not some shareware programmer from Wisconsin. If I am typing or otherwise working in a Window, no other application should ever be able to steal the focus, unless it’s warning me that my house is on fire or something.
  6. File directory trees the size of postage stamps. Related to the issue above. Ever get one of those slightly older applications that won’t let you size the directory lookup tree? With ever expanding hard drives and increasingly complex file directory structures, looking at your harddrive through a fixed size treeview that’s only 150 pixels square feels like being shoved in the trunk of a Yugo.
  7. Crappy error messages, especially when they are sentences and don’t end in a period. "Item not found". Great — which item? The name or even type of the item has got to be known by something in the app, otherwise, how could it be looked for?  Tell us for crying out loud! Or how about the old favorite "Error 332322". This isn’t a problem for me personally because I have, of course, memorized all the error codes for your application.
  8. CAPSLOCK keys. The person who thought putting the CAPSLOCK key above the SHIFT key and right below the TAB key should be rubbed vigorously with rough sandpaper and then placed in a bathtub full of lemon juice. [Ed:  Solution can be found here]
  9. Unnecessary modal dialog boxes that I have to click when it doesn’t make any difference. I love these. "You’ve done something really stupid. Press Ok to continue". Great. Thanks. I couldn’t have made it through the day without that totally, utterly meaningless and pointless message.
  10. Dialog boxes that have the negative answer on the left and the positive answer on the right. OK buttons go on the left. Cancel buttons go on the right. Don’t put the Delete button on the left and the Approve button on the right. It’s a gross violation of the laws of nature.

Nick’s Public Code Repository Update

By Nick at August 09, 2011 05:42
Filed Under: Delphi, Software Development

Some of you may remember the TextScrubber project I was writing about back on my Embarcadero blog.  (I’ll update that page really soon, like today…).  I’ve made two changes with that project:

  1. I’ve updated it to allow you to set it to run automatically on Windows startup.
  2. I’ve moved the repository from SVN and SourceForge over to Mercurial and BitBucket.

Now this may be a bit of an inconvenience to some of you, and I apologize.  First, if you don’t have the Mercurial command line tool installed, you should.  I’d venture to say that if you don’t have at least the command line tools for SVN, Git, and Mercurial installed, you can’t really call yourself a  true developer.  Second, I’m a Mercurial guy, and BitBucket is Mecca for Mercurial guys.  So you can get the code there.  Third, since I am now a Mercurial guy, SourceForge is no longer my cup of tea.  I’m going to move all my code there over to BitBucket.  (Note – this will not include the TurboPower projects, which I don’t consider “my code”….). 

My intent is to make my BitBucket page a central location for my code. I’ve created a “NickDemoCode” project to publish code I use to demonstrate things.  I’ve got a couple of other small projects there as well. I’d like to do what Marco did and have it be part of nickhodges.com, but I can’t seem to figure out how to do that.  (Anyone have any ideas? My ISP is pretty unhelpful, and this is not my area of expertise….)

So, if you are into great, awesome code, I’d recommend checking for updates to my public repository every 15 minutes or so.  You don’t want to get left behind.  Winking smile

Flotsam and Jetsam #41

By Nick at August 06, 2011 02:11
Filed Under: Flotsam and Jetsam

Flotsam and Jetsam #40

By Nick at July 27, 2011 07:50
Filed Under: Delphi, Flotsam and Jetsam, Software Development, TechBiz

Getting Giddy #4 Fixed

By Nick at July 10, 2011 11:52
Filed Under: Delphi, General, Software Development, Unit Testing

Okay, so I was getting all these emails about the fourth article in my “Getting Giddy” series of articles.  You guys kept saying it was missing and I kept saying “Hey, it’s right here!”.  And then finally I noticed – #4 and #5 were identical.  I must have done something stupid somewhere.  Well, I was able to track down the original article on my hard drive and restore it.  So now, the fourth article is as it should be, and all seems well with the universe.

Sorry for the confusion, and I appreciate the interest that these articles have generated.

Getting Giddy with Dependency Injection and Delphi Spring #4 – Dependency Injection Basics

By Nick at July 10, 2011 11:48
Filed Under:

So now after the first three parts, you are probably wondering – What the heck is he getting at?  Wasn’t he going to talk about dependency injection?  What the heck is this dependency injection anyway?

Okay, so let’s get down to more practical matters.  Earlier I recommended the Martin Fowler article that (I believe) actually coined the term “Dependency Injection”, but that article is a bit wonky.  I’m going to try to be a bit more practical and “examply” here, and of course, I’ll be showing everything in Delphi.  We’ve talked about the Law of Demeter and why writing testable code is a good idea, so now we’ll get down to it and show how we might actually go about doing what I’ve been talking about.

So, Dependency Injection.  Well, Dependency Injection (I’ll call it ‘DI’ from now on) is really just a way of providing functionality to a given class without creating a specific dependency on that class.  That is, the dependency is “injected” – provided -- for you.  There are a number of  ways to do this from the simple provision of a class to the use a complex framework and  attributes to define dependency instances.  By “specific” I mean that DI will allow you have control over how dependencies are provided.  For instance, you may want to control the injection of  dependency depending on whether you want to run things “for real” in production or what to run them as unit tests.

So by way of getting started, I’m going to define two rules (in addition to “Follow the Law of Demeter” and “Write Testable Code” that is…) that you should follow to make the use of DI easier and simpler. 

Rule #1:  Always code against interfaces

This might seem a bit weird, but I think it is a critical  practice to follow.  Interfaces define a given set of functionality, and that, really, is all you need to provide, right?  A given set of functionality?  A side-rule to this is “Never put a class in the interface section of a unit”.  Now that may seem a bit radical, but if you do this, you are pretty much guaranteed that you’ll follow the Law of Demeter.  A class in the implementation section of a Delphi unit cannot be coupled to outside of that unit.  It cannot be used or abused anywhere. 

Consider the following code: 

unit uNormalMathService;

interface

type
  IMathService = interface
    ['{BFC7867C-6098-4744-9774-35E0A8FE1A1D}']
    function Add(a, b: integer): integer;
    function Multiply(a, b: integer): integer;
  end;

function MathService: IMathService;

implementation

type

  TMathService = class(TInterfacedObject, IMathService)
    function Add(a, b: integer): integer;
    function Multiply(a, b: integer): integer;
  end;

{ TAdditionServiceImplemenation }

function TMathService.Add(a, b: integer): integer;
begin
  Result := a + b;
end;

function TMathService.Multiply(a, b: integer): integer;
begin
  Result := a * b;
end;

function MathService: IMathService;
begin
  Result := TMathService.Create;
end;

end.

This code provides a clearly defined set of functionality, implements that functionality, and makes that functionality available to anyone who wants to use it.  It does all of this without exposing any class at all to anyone outside of the unit.  All you get is an interface and a means of getting an interface via a function call.  (It’s simpler than you’d probably like it all to work, but it’s illustrative of the point….)  You can’t do anything other than use TMathService via the IMathService interface. You can’t abuse and otherwise mess around with TMathService because it is completely hidden from everyone. 

IMathService is easy to test, too.  You can grab an interface, and run tests on it to your hearts content.  And as we know, “easy to test” is a mantra akin to “look both ways before crossing the street” or “Don’t cross the streams”.

And in fact, as we move forward, a really cool part here is that you can provide different implementations of the IMathService interface if need be.  That can provide all kinds of flexibility in the areas of testing and production.  For instance,  if you somehow come up with some better way of adding and multiplying numbers, you can can change to the new way without having to worry about breaking anything at all.  Since it’s easy to test a specific interface implementation, you’ll have a complete suite of unit tests, and can change the implementation with confidence. 

Rule #2:  Keep Constructors Simple

Here’s a good rule of thumb for our second rule:  Don’t create anything in your constructor.  At all.  Ever.  Your constructors should do little else than assign values to field variables.  If your class needs something, it should ask for it.  To start, we’ll do the “asking” via parameters in the constructor.

Another thing to consider is that you should never have conditional code in your constructor.  If you are feeling the need to put an if statement in your constructor, you almost certainly need to break the given class up into two sibling classes with a common descendent.

Consider the following code: 

unit DIBasics;

interface

type

  TPizza = class

  end;

  TPizzaOven = class
    procedure Bake(aPizza: TPizza);
  end;

  TPizzaMaker = class
  private
    FPizza: TPizza;
    FPizzaOven: TPizzaOven;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

{ TPizzaMaker }

constructor TPizzaMaker.Create;
begin
  FPizza := TPizza.Create;
  FPizzaOven := TPizzaOven.Create;
end;

destructor TPizzaMaker.Destroy;
begin
  FPizza.Free;
  FPizzaOven.Free;
  inherited;
end;

{ TPizzaOven }

procedure TPizzaOven.Bake(aPizza: TPizza);
begin
  // bake the pizza
end;

end.


This code has all sorts of problems, no?  Right away, you can see all kinds of coupling.  The TPizzaOven class is directly dependent on TPizza.  The TPizzaMaker class depends directly on TPizza and TPizzaOven.  What if you want to bake a TPepperoniPizza? 

Basically this code defies practically everything that I’ve been telling you not to do. 

Okay, so, let’s apply the most basic form of DI on this code.  I’m not sure if it has a name, but I’ll call it “Dependency Injection via Constructor Parameters”  (as opposed to “Constructor Injection” which is, as we’ll see, something entirely different):

unit DILittleBetter;

interface

type

  TPizza = class

  end;

  TPizzaOven = class
  private
    FPizza: TPizza;
  public
    constructor Create(aPizza: TPizza);
    procedure Bake;
  end;

  TPizzaMaker = class
  private
    FPizzaOven: TPizzaOven;
  public
    constructor Create(aPizzaOven: TPizzaOven);
  end;

implementation

{ TPizzaOven }

procedure TPizzaOven.Bake;
begin
  // bake the pizza
end;

constructor TPizzaOven.Create(aPizza: TPizza);
begin
  FPizza := aPizza;
end;

{ TPizzaMaker }

constructor TPizzaMaker.Create(aPizzaOven: TPizzaOven);
begin
  FPizzaOven := aPizzaOven;
end;


end.

Here, the thing we’ve done to reduce the coupling and the dependency is to have the classes not create their own instances of what they need, but instead, to “ask” for those instances via the constructor.  The TPizzaOven and TPizzaMaker classes get their dependencies provided to them via parameters on their constructors.  The constructors merely assign the passed in references to local variables.  This way, the “link” between the classes is much looser and the flexibility of the whole system is increased while making the classes less coupled together. 

And here’s another reason to use interfaces – the above code doesn’t really cleanly answer the question of the lifetime of the classes passed to the constructors.  Who is in charge of freeing the classes – the caller or the class itself?  The TPizzaMaker and TPizzaOven classes assume that the classes passed to them will be freed elsewhere but there may be occasions when that isn’t the pattern you want to follow .  If you use interfaces for everything, you don’t’ have to worry about the lifetime of your objects – Delphi’s reference counted interfaces will be “garbage collected” for you (for lack of a better term). 

So at its base, DI is the notion that a class should ask for the things it needs and not create those things itself.  There are any number of ways to ask for a given need.  “Dependency Injection via Constructor Parameter” is a very nice way to inject dependencies into a class.  It can get a little messy though, because in order to create a class, you often have to create multiple classes to pass as parameters. 

So, what if you had a system that allowed you to inject dependencies into your classes without even having to really create the classes in the first place?  What if instances of your dependencies could just auto-magically appear out of nowhere without you having to really do anything much at all?

Well, that is what DI frameworks like Spring do, and we’ll take a look at that in our next installment. 

Flotsam and Jetsam #39

By Nick at July 10, 2011 09:25
Filed Under: Flotsam and Jetsam, Delphi

Flotsam and Jetsam #38

By Nick at July 07, 2011 00:26
Filed Under: Delphi, Flotsam and Jetsam, Software Development

A Bunch of Stuff I’d Like to See Embarcadero Do

By Nick at July 05, 2011 13:22
Filed Under: Delphi, Tech Stuff, TechBiz

There are a bunch of things that I’d like to see Embarcadero do.  I’ve listed and discussed some of them below.  I’ll probably think of more later.  Winking smile  They are in no particular order, and they are not grouped in any particular way.  They are a bit random, and range from business decisions to minor technological decisions. Where it makes sense, I’ve linked the titles to the entries on http://delphi.uservoice.com/ so that you can vote for the items if you see fit.

I’d like to see Embarcadero:

  1. Provide an Enterprise-level MVC web framework for Delphi.  This almost seems like a no brainer to me. Ruby on Rails has had a profound impact on web development and development in general.   In the .Net world, MVC has become the leading ASP.NET development method,winning over hearts and minds from WinForms.  The general idea of MVC is becoming the norm for much of the development world – separate those concerns!. Delphi’s new RTTI capabilities would actually make this kind of framework very, very possible and very, very cool.  And Delphi already has a very powerful and capable web infrastructure to build on:  good, old, and venerable WebBroker.  There are even existing frameworks out there that could be leveraged, including the G Framework.   There is a business opportunity here for Embarcadero, if not for an enterprising third-party Delphi developer.  A native, ISAPI based MVC framework in Delphi?  That would be very, very sweet.
  2. Stop trying to do other stuff and invest in Delphi.  This one has been one of my huge frustrations over the years.  Delphi is a profitable product, but no matter who owns or runs the show,  the profits always seem to get skimmed off to fund other “next big thing” projects of, well, questionable benefit at best.   Remember “SDO” taking the market by storm? Yeah, me neither. AppWave seems to be interesting and have a lot going for it, but I personally would rather have seen that effort invested back into Delphi.  I hate to think about where Delphi might be today if it hadn’t been used to fund other projects and instead been allowed to use it’s profits for it’s own development.  Delphi could use a year or two of un-distracted attention from its owner. 
  3. Create a Javascript/HTML development tool.  I’ve always said “As assembler is to the Intel chip, so Javascript is to the browser”.  James Governor has it right:  “Learning Javascript used to mean you weren't a "serious software developer". Today, not learning Javascript means the same thing.”  A powerful, feature rich RAD development tool for Javascript and JQuery would be really cool and a great new product for Embarcadero.  Maybe RADPHP could be steered in that direction?
  4. Make Dependency Injection part of the RTL: If you haven’t figured it out yet, I’m a big believer in Dependency Injection.  So much so, that I think that if you aren’t doing Dependency Injection, then you are doing it wrong.  Incorporating a DI Container into the Delphi RTL would be very cool.  Again, Generics, anonymous methods, and the new RTTI makes is very easy and powerful, and there are open source projects to leverage and build on (like my favorite, Delphi Spring).
  5. Do one thing at a time and do it really well:  This is the one that I wish they would do the most:  Take the product forward one step at a time. For instance, the next release should have as it’s main focus 64-bit Delphi and only 64-bit Delphi. That’s it.  Other improvements can be made, of course, but clearly that should be the “big one”, and it should be the only “big one”.  Don’t try to do two or three “big ones” in a single release. Make each release focused on a big, single step forward, executed thoroughly and solidly.  The product will be fine as long as it shows steady, sustained improvement.  Many large improvements executed all at once is not what the market wants.  Focus and deliberately move forward.

That’s all for now – I’ll probably have more as I think of them, but that ought to be food for thought for while

Changes to the Website

By Nick at July 01, 2011 10:08
Filed Under: General

As you’ve probably noticed, there have been some changes to my website here.  I thought I’d list what I did:

  • I updated the engine to BlogEngine.Net 2.5.
  • I updated the theme as well.  I wanted one where the main content isn’t fixed in width. I’ve been posting a lot of code samples, and having a fixed with for those wasn’t working like I wanted.  I also thought it was time for a “fresh look”.  I’ll be tweaking the theme going forward – I’m still not happy with all the font sizes.
  • I added a Google Plus One button to each post after the buttons from AddThis. I also made those buttons a bit more prominent.  Feel free to click those buttons if you like what you see.  Winking smile 

Of course, if you notice any problems, issues, etc., or have any feedback and/or suggestions, please let me know.

Accessing Private Stuff with Interfaces

By Nick at June 27, 2011 08:38
Filed Under: Delphi, Tech Stuff

I have to admit that the following code surprised me.  I guess it makes sense, but I wouldn’t have guessed that you can expose private functionality via an interface like this.  Interesting. 

program DoPrivateStuff;

{$APPTYPE CONSOLE}

uses
  SysUtils;


type

  ITestInterface = interface
    procedure DoThisPrivateThing;
    procedure DoThisPublicThing;
  end;

  TTestClass = class(TInterfacedObject, ITestInterface)
  private
    procedure DoThisPrivateThing;
  public
    procedure DoThisPublicThing;
  end;

{ TTestClass }

procedure TTestClass.DoThisPublicThing;
begin
  Writeln('Doing a public thing');
end;

procedure TTestClass.DoThisPrivateThing;
begin
  WriteLn('Doing a private thing');
end;

var
   Test: ITestInterface;

begin
  try
    Test := TTestClass.Create;
    Test.DoThisPrivateThing;
    Test.DoThisPublicThing;
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Getting Giddy with Dependency Injection and Delphi Spring #5 – Delphi Spring Basics

By Nick at June 26, 2011 13:12
Filed Under: Delphi, Software Development

 

Remember, you can download the Delphi Spring Framework on Google Code.

Introduction

Okay, so we are finally at the point where we can actually start using a framework to do some of the things that we want to do.  So far we’ve seen how the Law of Demeter is important to good code design.  We’ve looked at how important it is to write testable code by reducing the dependencies between objects, and we’ve seen how it’s good to code against interfaces and to keep our constructors simple. I’m finally going to make good on my promise to show you how to write useful code in a unit with nothing in the interface section. 

I hope I’m doing a good job describing why and how you want to use a Dependency Injection framework.  I hope by the end of this, you can see how to use the Delphi Spring Framework.  However, I’m doing a very imperfect job of describing the motivations and reasons behind why you want to do dependency injection. However, all is not lost – I strongly recommend that you watch this outstanding episode of DotNetRocks TV, where a really smart guy (with a delightful Canadian accent – he sounds just like my brother-in-law) named James Kovacs explains the whole underpinnings of Dependency Injection and why it’s good.  He does the presentation in C#, but don’t let that put you Delphi guys off --  the ideas are all there. 

Problems With “DI via Constructor Parameters”

In the last episode, I talked about two rules that you should follow:

  1. Always code against interfaces
  2. Keep your constructors simple

We looked at how exposing only an interface will create clean, uncoupled, and testable code, and how keeping constructors simple will decrease one classes dependency on another.  We saw an example of what I called “Dependency Injection via Constructor Parameters” (DICP) where you don’t create internal classes yourself, but let them get passed in via parameters on a constructor. 

DICP allows you to create the services (classes) you need outside of the consuming class itself, but it still requires that you create specific classes you want in specific places in your code.  Despite having a certain level of inversion of control, you are still coupled to the specific class.  Consider the following code, based on our Pizza Oven code from the last installment:

var
  MyPizzaOven: TPizzaOven;
  MyPizza: TPizza;
begin
  MyPizza := TPizza.Create;
  MyPizzaOven := TPizzaOven.Create(MyPizza);
end;

This code is better than creating the TPizza class inside the constructor of TPizzaOven, but we still have the problem of the TPizza class and the TPizzaOven class being coupled together via the uses clause – TPizzaOven needs to know about the TPizza class and how it is declared. 

Even if we re-declare TPizza as an interface – IPizza – we still have to know how to create an instance of TPizza for the IPizza interface, and we aren’t all that much more decoupled than we were before – TPizzaOven still has to know about the specific declaration of TPizza. In fact, the code above really wouldn’t change at all if the MyPizza variable were an IPizza instead of a TPizza,right?

But what if there were a way to get an interface implementation without having to know anything about the specific implementation of that interface?   Now that would really decouple things and truly separate the interface from the functionality. If only there were a framework written in Delphi that would let you do this.  If only……!

The Spring Container

Okay, I was joshing – there is such a thing:  The Delphi Spring Container does exactly that.  A Dependency Injection container is a class that can hold references to interfaces and classes that implement them.  You can register specific implementations of interfaces in the container.  If you need an implementation of an interface, you ask the container, and it provides a reference to that implementation via the given interface.   When you need an implemented interface, you reference only the container, and thus there is no direct connection between the class needing the implementation and the implementation itself.  Pretty sweet, huh?

So how does this work?  The first thing you’ll likely want to do is to create a singleton implementation of the Spring Container.  I’ve created the following unit called uServiceLocator, which wraps up the Spring Container in a Singleton:

unit uServiceLocator;

interface

uses
        Spring.DI
      ;

  function ServiceLocator: TContainer;

implementation

var
  FContainer: TContainer;

function ServiceLocator: TContainer;
begin
  if FContainer = nil then
  begin
    FContainer := TContainer.Create;
  end;
  Result := FContainer;
end;


end.

The uServiceLocator uses the Spring.DI unit from the Delphi Spring Framework where the TContainer class is declared. I have named my container "ServiceLocator" because it, well, locates services. SmileYou can use this unit anywhere you need to register classes and interfaces, as well as anywhere you need to use those registered interfaces.

TContainer is a powerful class that leverages both Generics and anonymous methods to let you register classes that implement given interfaces.  In later articles, I’ll delve a little deeper into the mysterious inner workings of TContainer, but for now, we’ll just look at the practicalities of how it is used.

Registering With The Container

Now, if you want to use the container, either to register classes with interfaces, or to consume a given interface, all you need to is use the uServiceLocator unit and not any unit that actually declares classes.  In fact, you can declare your classes in the implementation section of the unit and leave only an interface in the interface section.  Remember the uNormalMathService unit from last time?   Now, we can declare it as follows: 

unit uNormalMathService;

interface

type
  IMathService = interface
    ['{BFC7867C-6098-4744-9774-35E0A8FE1A1D}']
    function Add(a, b: integer): integer;
    function Multiply(a, b: integer): integer;
  end;

implementation

uses
  uServiceLocator;
type

  TNormalMathServiceImplemenation = class(TInterfacedObject, IMathService)
    function Add(a, b: integer): integer;
    function Multiply(a, b: integer): integer;
  end;

{ TNormalMathServiceImplemenation }

function TNormalMathServiceImplemenation .Add(a, b: integer): integer;
begin
  Result := a + b;
end;

function TNormalMathServiceImplemenation .Multiply(a, b: integer): integer;
begin
  Result := a * b;
end;

procedure RegisterNormalMathService;
begin
  ServiceLocator.RegisterComponent<TNormalMathServiceImplemenation>.Implements<IMathService>('Normal');
  ServiceLocator.Build;
end;

initialization
  RegisterNormalMathService;

end.

First, note that the IMathService interface is the only thing available for use outside of the unit. Everything else is hidden in the implementation section.  Obviously, the “money code” here is the RegisterNormalMathService procedure. This is where the implementation of IMathService gets registered.  The procedure itself gets called in the unit’s initialization section, so the mere act of using the unit ensures that the TNormalAdditionService is registered and available for use by any other unit that uses the ServiceLocator.  The call to ServiceLocator.Build simply ensures that the TContainer is ready to answer requests for implementations of interfaces.

So what is happening in the RegisterNormalMathService call?  It’s almost self-explanatory.  The code performs pretty much as it reads: “Register the class called TNormalMathServiceImplementation, which implements the IMathService interface, under the name "Normal”.  (That’s what the last string parameter is – a named reference to the interface.  This allows you to register multiple implementations of a given interface and request them by name).

Nota Bene:  if you are going to provide multiple implementations of a given interface, you can declare that interface in a separate unit, use that new unit in the implementation section, and end up with no code at all in the interface section of your unit.  See, I told you it would work.  Winking smile

And once the service is registered, you can use it in a completely decoupled way:

unit uCalculator;

interface


implementation

uses
    uServiceLocator, uNormalMathService;

type
  TCalculator = class
  private
    FMathService: IMathService;
  public
    constructor Create;
    function Addition(a, b: integer): integer;
    function Multiplication(a, b: integer): integer;
  end;

constructor TCalculator.Create;
begin
  FMathService := ServiceLocator.Resolve<IMathService>('Normal');
end;

function TCalculator.Addition(a, b: integer): integer;
begin
  Result := FMathService.Add(a, b);
end;


function TCalculator.Multiplication(a, b: integer): integer;
begin
  Result := FMathService.Multiply(a, b);
end;

end.

In this case, the “money code” happens in the class’s constructor, where the ServiceLocator is asked to “resolve” (i.e., provide) a working instance of IMathService, using the implementation registered under the name 'Normal'. The Container then goes and looks into its list of registered items, finds the correct implementation, creates an instance of that class, and returns it as an interfaces.  All of that happens “auto-magically” inside the inner-workings of the TContainer class.

Later on we’ll see how you can control the lifetime of the created classes, pool them, or create instances as a Singleton.  You can even have complete control over how the resulting class is created via the power of anonymous methods. 

Note that the class knows nothing about anything other than IMathService.  It does use the uNormalMathService, but the implementation of that class is completely hidden.   The only reason that uNormalMathService is in the uses clause is because that is where the IMathService interface is declared.  If you really want, you can do as the quote block above says and declare the interface in a separate unit and not even require the use of the unit that implements IMathService at all.

Conclusion

Thus, we have a simple example of using the Delphi Spring DI Container that completely decouples the implementation of a class from the consumer of that class.  In the above example, the TCalculator class knows nothing of nor is connected in anyway to the implementation of the IMathService interface.  All of this happens inside of the Delphi Spring container. 

So far, this is just a simple, basic look at what the Delphi Spring Container can do.  The Delphi Spring Framework can actually automatically and seamlessly create implementations for interfaces without writing any code at all.  So stay tuned for that in coming installments. 

Flotsam and Jetsam #37

By Nick at June 22, 2011 03:06
Filed Under: Delphi, Flotsam and Jetsam, Tech Stuff
  • Marco Cantu has published his new book on Delphi XE.  I’ve been given an advanced copy (thanks, Marco!) and as you’d expect, it is excellent.  We are going to buy some copies here at Gateway Ticketing for use in our transition to Delphi XE.  As with everything Marco does, it is highly recommended
  • There a new Facebook group for Delphi Developers that seems to have a lot of activity.  You might consider joining.  It would be good for Delphi people to congregate in a single place on Facebook to share links and information, and this might be the place. 
  • And speaking of Facebook, you can now ’Like’ Embarcadero’s AppWave on Facebook.  I’m still not clear on exactly where all this AppWave thing is going, but it does look interesting.  I wonder what affect the “appstore” in Windows 8 will have on it.  I guess one advantage that AppWave has is that it is here right now, and Windows 8 is still pretty much vaporware at this point.
  • I went to see the Green Lantern this past weekend.  Highly recommended – I have no idea what all the bad reviews were about.  Great comic book movie.  (Those reviewers know that the Green Lantern is a comic book movie, right?)  The tech angle here is that it was the first time that I had seen a movie in 3D.  My take?  I never want to see a movie – any move, I don’t care if it’s a “blockbuster” or not – in 2D again. It was a terrific experience. This is a great feature that will definitely get me in the theater more. I have been going to the theatre less and less because of Netflix, but if I can see the upcoming Harry Potter movie in 3D, I will.  Looking forward to it being the normal experience on TV.
  • David I has been at Borland, Inprise, Borland, CodeGear, and now Embarcadero for 26 years.  He’s seen it all.  Congratulations to a titan of the industry – and a great guy.  I’ve known David for many years – since I met him at a PC User group at the Naval Postgraduate School in around 1994 – and it’s been an honor to be his friend.
  • I love a good story like this:  Throw Away that Hotel Soap.  There is staggering waste in our economy (anyone buying cases of plastic bottles of water – I’m looking at you…) and this is the kind of thing I love to see.

Flotsam and Jetsam #36

By Nick at June 19, 2011 04:51
Filed Under: Flotsam and Jetsam, Delphi

My Book

A Pithy Quote for You

"Nothing is wrong with California that a rise in the ocean level wouldn't cure."    –  Ross MacDonald

Amazon Gift Cards

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.