Go Back

Polymorphing different Types


So my friend (though not good enough friend to be my ‘boatfriend’) ran into a programming issue the other day at work. He had two objectswith similar data and no behavior (vb6 style data/procedural programming). Unfortunately,these two objects did NOT inherit from the same base object and they were beingused similarly in an asp.net code behind page but there was no clearabstraction.

 

If(foo.GetType() == typeof(recurringTransaction))

{

Foo1();

}

Else

{

Foo2();

}

 

So basically “foo” could be one of two different types… arecurring transfer or a single transfer. Depending on the type, we’d get adifferent UI behavior.

 

This is clearly an opportunity for polymorphism, but we didNOT have control of these objects! They were vendor code.

 

So what do you do in this situation?

 

Well directly to the point, you would create a new baseclass called “Transfer” and then use composition to encapsulate the dataobjects. Making something like this:

 

What’s that look like in code?

     class OldSingleTransfer

    {

        //Some data

    }

    class OldRecurringTransfer

    {

        //Some similiar data

    }

    abstract class Transfer

    {

        public abstract void MyUIBehavior();

    }

    class SingleTransfer : Transfer

    {

        OldSingleTransfer instance;

        public override void MyUIBehavior()

        {

            //Specific single transfer code

        }

    }

    class RecurringTransfer : Transfer

    {

        OldRecurringTransfer instance;

        public override void MyUIBehavior()

        {

            //specific recurring transfer code

        }

    }

 Now you can just do foo.MyUIBehavior(); and be done with it.

 I know what you're thinking... GOD that's a LOT of code just to do this one thing. That's not how i would do this.

Well, yes you're right this is more code initially... however in reality what we had was 40-100 lines of 'type specific' code that was mostly all repeated for both types. We've eliminated all of that duplication and left ourselves with an easier set of operations to maintain and reduced the complexity by removing the conditional logic.

There were bugs lurking in this code... for example what would happen if you made a third type of transfer? it would have hit the "else" condition... meaning "single transfer". What if it was a scheduled transfer?

Facebook DZone It! Digg It! StumbleUpon Technorati Del.icio.us NewsVine Reddit Blinklist Furl it!

Comments  7

  • Ben Coffman 8/29/2009 12:00:00 AM

    Good quick post JP.

    Also I noticed your theme's menu doesn't like safari too much. Just a heads up, not sure a Windows head would care.
  • James Peckham 8/30/2009 12:00:00 AM

    Thanks for the the comment and the information... I won't even bother making excuses for the theme or my lack of browser testing. I really should spend some time on it. I basically just took the default theme that came with sitefinity and then I made it wider to handle the code samples I posted.
  • Chris Leon 9/3/2009 12:00:00 AM

    To handle multiple types of transfers, maybe it could be simplified with Unity something like this:

    abstract class Transfer
    {
      public abstract void MyUIBehavior();
    }
    ...

    class ScheduledTransfer : Transfer { ... }
    class SingleTransfer : Transfer { ... }
    class RecurringTransfer : Transfer { ... }
    class JamesSavingsToChrisCheckingTransfer : Transfer { ... }
    ...

    void DoSomeUIStuff(string transferType)
    {
      Transfer theTransfer = IoC.Resolve<Transfer>(transferType);
      theTransfer.MyUIBehavior();
    }

    Legacy transfer types would be wrapped in the new types, just like you have above. Just a thought...
  • James Peckham 9/3/2009 12:00:00 AM

    For those not familiar. Chris i think is talking about this:

    an IoC (inversion of ... control?) container?

    anyhow. the idea you're saying chris is that inside of my web applicaiton i would utilize IoC to resolve the Transfer type by passing in the transfer type as a string (representing the namespace.class)?

    so like transferType would be something like "JPeckham.Transfers.JamesSavingsToChrisCheckingTransfer"

    So the UI then is not dependent on any of the types at all? it only uses strings to instantiate transfers?

    Is IOC just basically a factory pattern?
  • Chris Leon 9/4/2009 12:00:00 AM

    Yes, that is the Unity I'm talking about. Yes, the string represents the name/key of the type you want to create. And so it allows the UI to not know or care about any of the specific Transfer implementations, as you said; it only has to know the string name to use.

    The names could even be put in a static class containing a bunch of string constants, so you only have to update one class if the names/keys ever needs to change. Or you could just change the .config file's name/key info if you don't want to re-release the code for something dumb like a key name change. 

    Obviously you could go crazy with this and isolate your app code completely from any specific business object implementations of any kind. That would make for a more complex .config file (or wherever you store your config data). And of course you have to consider maintainability, plus there is a performance hit for all this decoupling yuminess. I don't remember for sure, but I thought Unity had some built-in optimizations to reduce the number of reflections/config reads...
  • James Peckham 9/4/2009 12:00:00 AM

    Like this chris?


            IUnityContainer container = new UnityContainer();
                container.RegisterType<Transfer, SingleTransfer>("single");
                container.RegisterType<Transfer, RecurringTransfer>("recurring");

                Transfer instance = container.Resolve<Transfer>("recurring");
                instance.MyUIBehavior();
                Console.ReadKey();
  • Chris Leon 9/8/2009 12:00:00 AM

    You could do it that way. You can also do all the type/name registering via configuration. The latter would allow you to access a concrete type at runtime without explicitly refering to it at compile time, except by name of course. Either way works. I think this is the example we worked from:

Post a comment!
  1. Formatting options