Amazon.com Widgets Getting Giddy with Dependency Injection and Delphi Spring #9 – One Interface, Many Implementations

Getting Giddy with Dependency Injection and Delphi Spring #9 – One Interface, Many Implementations

By Nick at November 07, 2011 11:27
Filed Under: Delphi, Software Development

So far, we’ve been registering interfaces and implementations in a one-to-one relationship.  Each interface has one implementing class registered against it.  But what if you want to implement an interface many different ways, choosing which implementation to use depending on user input or other external factors?

As always, you can download the Delphi Spring Framework from GoogleCode.

Well, lucky for us, the Spring Container lets us do just that.  The Delphi Spring Framework container registration system allows you to specify a name for any giving implementation registration, thus distinguishing different registrations from on another, even if you register multiple implementers for the same interface. 

If you register multiple implementers for a given interface without specifying a name for each one, then the “last one in wins'”.

So, for instance, you might declare a simple credit card interface as follows:

type
  ICreditCard = interface
    ['{6490640C-0E2B-4F7D-908C-0E6A74DCC0A0}']
    function IsValid(aCreditCardNumber: string): boolean;
    function ChargeAmount(aCreditCardNumber: string; aAmount: Double): Boolean;
  end;

There are any number of credit cards that customers might want to use, so you’ll need to have credit card implementations for the various common vendors:

  GlobalContainer.RegisterType<TVisa>.Implements<ICreditCard>('VISA');
  GlobalContainer.RegisterType<TMasterCard>.Implements<ICreditCard>('MasterCard');
  GlobalContainer.RegisterType<TDiscover>.Implements<ICreditCard>('Discover');
  GlobalContainer.RegisterType<TAMEX>.Implements<ICreditCard>('AMEX');

This code registers four different classes (TVisa, TMasterCard, TDiscover, TAMEX) for the same interface (ICreditCard) via the string parameter on the GetService call.  Once these are registered, you can pick and choose whichever credit card processing class you want as the implementation of ICreditCard.  You can even change the selection at runtime based on, say, user input or different orders being processed, etc. 

For instance, if you have four radio buttons that allow the user to select one of four credit cards, you can do the following:

var
   CurrentCard: ICreditCard

...

procedure TMultipleImplementationsForm.RadioButton1Click(Sender: TObject);
begin
  CurrentCard := ServiceLocator.GetService<ICreditCard>('VISA');
end;

procedure TMultipleImplementationsForm.RadioButton2Click(Sender: TObject);
begin
  CurrentCard := ServiceLocator.GetService<ICreditCard>('MasterCard');
end;

procedure TMultipleImplementationsForm.RadioButton3Click(Sender: TObject);
begin
  CurrentCard := ServiceLocator.GetService<ICreditCard>('Discover');
end;

procedure TMultipleImplementationsForm.RadioButton4Click(Sender: TObject);
begin
  CurrentCard := ServiceLocator.GetService<ICreditCard>('AMEX');
end;

The above code will assign an instance of the appropriate implementing object to the single variable CurrentCard depending on which radio button the user selects.  The proper object is returned based upon the string parameter passed to the GetService call.  That string value, of course, corresponds to the object registered with that same string as shown above. 

Thus, you can register by name and then use as many implementing objects for a single interface as you want.   This is obviously very powerful, as you can choose from any number of implementations as well as add new implementations anytime you want.

A sample application showing this technique as well as some other interesting features can be found in the samples that come along with the Delphi Spring Framework

blog comments powered by Disqus

My Book

A Pithy Quote for You

"No matter how rich you become, how famous or powerful, when you die the size of your funeral will still pretty much depend on the weather."    –  Michael Pritchard

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.