Saturday, August 16, 2008

Boba Fett, Greedo, and StructureMap

"Austin, Texas. You will never find a more wretched hive of scum and villainy. We must be cautious."

These words were uttered by an inhabitant of the the wastelands around Austin.  Shrouded in mystery, most people think he's nothing more than a crazy old wizard.  He keeps to himself mostly, occasionally seen associating with the lowest sort of riff-raff, and forever spouting mumbo-jumbo about some bizarre religion he follows.  But there are those who know his true identity, that he is in fact the legendary Jedi Obi-Wan Kejeremy.

Ahhh, forget it.  I just can't keep up the extended metaphor anymore.  In keeping with my last post, I was going to go into some long, labored Star-Warsy exposition about Jeremy's new padawans, Chad and Josh, and the work they've done with him on a secret weapon called StructureMap.  But it's late, I'm tired, and I want to finish this post tonight, so let's just skip right to the point, mmmmm-kay?  I took the code I wrote for the last post and used StructureMap to decouple things a bit further after reading through Chad's articles (here and here) as well as a bunch of stuff Jeremy has written about StructureMap.  Since there are still those among us who are fashionably late to the .NET 3.5 party, I used StructureMap 2.0.  I also thought a bit more about the design and changed some things around after looking at Josh's code (and, let's be honest, outright stealing some of his code).  And no, I didn't write tests for this stuff, and yes, I know that makes me a lazy jerk.  See sentence four in this paragraph.

So here's how the Program class changed:

   1: class Program
   2: {
   3:     private static void Main(string[] args)
   4:     {
   5:         Configure();
   6:  
   7:         IAppEngine appEngine = ObjectFactory.GetInstance<IAppEngine>();
   8:         appEngine.Run();
   9:     }
  10:  
  11:     private static void Configure()
  12:     {
  13:         StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
  14:         StructureMapConfiguration.BuildInstancesOf<IAppEngine>().TheDefaultIsConcreteType<AppEngine>();
  15:         StructureMapConfiguration.BuildInstancesOf<IOutputDisplay>().TheDefaultIsConcreteType<ConsoleOutputDisplay>();
  16:         StructureMapConfiguration.BuildInstancesOf<IStuffStrategy>().TheDefaultIsConcreteType<LitterOfKittens>();
  17:         StructureMapConfiguration.BuildInstancesOf<IDrinkingEstablishment>()
  18:             .TheDefaultIs(
  19:             Registry.Instance<IDrinkingEstablishment>()
  20:                 .UsingConcreteType<Cantina>()
  21:                 .WithProperty("name").EqualTo("Mos Eisley Cantina")
  22:             );
  23:     }
  24: }

I love it!  That Configure() method allowed me to break almost every dependency.  The only time I'm actually using the new keyword is in the AppEngine (lines 15 and 22), and if I weren't falling asleep I could probably figure out a way to get rid of it there too.

   1: public class AppEngine : IAppEngine
   2: {
   3:     private IDrinkingEstablishment _drinkingEstablishment;
   4:     private IOutputDisplay _outputDisplay;
   5:  
   6:     public AppEngine(IDrinkingEstablishment drinkingEstablishment, IOutputDisplay outputDisplay)
   7:     {
   8:         _drinkingEstablishment = drinkingEstablishment;
   9:         _outputDisplay = outputDisplay;
  10:     }
  11:  
  12:     public void Run()
  13:     {
  14:         GetANewPatron("Boba Fett");
  15:         _drinkingEstablishment.SetStuffStrategy(200, new ConfusionOfWeasels());
  16:         GetANewPatron("Greedo");
  17:         _outputDisplay.Get();
  18:     }
  19:  
  20:     private void GetANewPatron(string name)
  21:     {
  22:         IPatron patron = new BountyHunter(name);
  23:         _drinkingEstablishment.WelcomePatron(patron);
  24:         foreach (IStuff thing in patron.Basket)
  25:             _outputDisplay.Put(thing.DoSomething(patron));
  26:     }
  27: }

So, without further adieu, you can download my little experiment and peruse it to your heart's content if you just click right here.  Laugh at it all you want to.  I'll be asleep.

Share this post :

Boba Fett, Greedo, and the Strategy Pattern

bobafett Bounty hunting is a difficult line of work.  Think about it:  1) Jobs are generally consulting gigs rather than full-time employment.   2) You're brought in at the last minute, usually to clean up someone else's mess, under a lot of pressure to save the day.  3) There are long hours, difficult problems to solve, and any benefits or vacation days come out of your own back pocket.  So give Boba Fett and Greedo a little respect.  They're willing to go flying off to the seedy backwaters of the galaxy, at great personal expense, mind you, turning over every stone until they find the Rebel scum they've been told to bring in.  All because the megalomaniacal creeps they work for run huge bureaucratic organizations filled with nothing but boot-licking sycophants and lackeys who can't seem to catch one measly smuggler and his smelly walking-carpet sidekick.  And if they should happen to run across this smuggler, who knows what kind of lethal stunt this half-witted, scruffy-looking nerf herder is liable to pull to get away from them.  Here's just one example:

image 

Shocking, isn't it?  I know.  It's called the StrategyPattern, and if you're not looking out for it, well you might just end up with some brand new ventilation courtesy of Han's blaster.  Here's how it works:

Let's say you find yourself in a particular context, like, say, a cantina on a desert planet.  Bartender gives you a drink, and you're parched, so you reach for it.  But wait!!  Is that beaker really filled with good old Membrosia?  How do you know nobody has slipped the bartender a couple hundred galactic credits along with a bottle marked "Membrosia", but which is really heavily spiked with carsunum?  What does the bartender care?  All he knows is he gets a free bottle and two hundred credits out of the deal - makes no difference to him.  People keel over in his place all the time.  Seems like a pretty good strategy for knocking you off, wouldn't you say?

Here's another strategy pattern scenario I bet you didn't think about:

image

Boba Fett is a bounty hunter. 

   1: public class BountyHunter : ICantinaPatron
   2: {
   3:     private string _name;
   4:     private IList<IStuff> _basket = new List<IStuff>();
   5:  
   6:     public BountyHunter(string name)
   7:     {
   8:         _name = name;
   9:     }
  10:  
  11:     public string Name
  12:     {
  13:         get { return _name; }
  14:     }
  15:  
  16:     public IList<IStuff> Basket
  17:     {
  18:         get { return _basket; }
  19:     }
  20: }

He happens to walk into the Mos Eisley cantina on a day when they're giving away stuff to all the cantina patrons: today, it's fuzzy animals. (Don't ask me.  Some corporate marketing idiot from the cantina's Membrosia distributor thought it would be a good promotional gimmick.) 

   1: public class Cantina
   2: {
   3:     private int _bribe;
   4:     private StuffStrategy _stuffStrategy = new LitterOfKittens();
   5:  
   6:     public void AcceptBribe(int bribe)
   7:     {
   8:         _bribe = bribe;
   9:     }
  10:  
  11:     public void SetStuffStrategy(StuffStrategy stuffStrategy)
  12:     {
  13:         if (_bribe > 100) _stuffStrategy = stuffStrategy;
  14:     }
  15:  
  16:     public ICantinaPatron GetPatron(string name)
  17:     {
  18:         ICantinaPatron cantinaPatron = new BountyHunter(name);
  19:         _stuffStrategy.GetStuff(cantinaPatron);
  20:         return cantinaPatron;
  21:     }
  22: }
  23:  
  24: public abstract class StuffStrategy
  25: {
  26:     public abstract void GetStuff(ICantinaPatron cantinaPatron);
  27: }
  28:  
  29: public interface IStuff
  30: {
  31:     string DoSomething(ICantinaPatron patron);
  32: }
  33:  
  34: public interface IFuzzyAnimal : IStuff
  35: {
  36:     string Name { get; }
  37:     string MakeNoise();
  38:     string Play();
  39: }
  40:  
  41:  

So when Boba Fett takes his basket of stuff from the barkeep and opens it up to see what he got, he discovers a litter of adorable kittens named Blossom, Minty, Butterscotch, Cotton Candy, Blue Belle, Snuzzle, and Rainbow Dash.

   1: public class Kitten : IFuzzyAnimal
   2: {
   3:     private string _name;
   4:     private string _playmate;
   5:  
   6:     public Kitten(string name)
   7:     {
   8:         _name = name;
   9:     }
  10:  
  11:     public string Name
  12:     {
  13:         get { return _name; }
  14:     }
  15:  
  16:     public string MakeNoise()
  17:     {
  18:         return
  19:             "Hi, " + _playmate + "!  My name is " + _name +
  20:             ", and I'm a kitten!  Meow!  prrrrr  prrrrrrrrrrrr";
  21:     }
  22:  
  23:     public string Play()
  24:     {
  25:         return _name + " blinks her big grey eyes and paws " + _playmate + "'s finger adorably.";
  26:     }
  27:  
  28:     public string DoSomething(ICantinaPatron patron)
  29:     {
  30:         _playmate = patron.Name;
  31:         return MakeNoise() + "\r\n" + Play() + "\r\n";
  32:     }
  33: }
  34:  
  35: public class LitterOfKittens : StuffStrategy
  36: {
  37:     public override void GetStuff(ICantinaPatron cantinaPatron)
  38:     {
  39:         cantinaPatron.Basket.Add(new Kitten("Blossom"));
  40:         cantinaPatron.Basket.Add(new Kitten("Minty"));
  41:         cantinaPatron.Basket.Add(new Kitten("Butterscotch"));
  42:         cantinaPatron.Basket.Add(new Kitten("Cotton Candy"));
  43:         cantinaPatron.Basket.Add(new Kitten("Blue Belle"));
  44:         cantinaPatron.Basket.Add(new Kitten("Snuzzle"));
  45:         cantinaPatron.Basket.Add(new Kitten("Rainbow Dash"));
  46:     }
  47: }

Here's what happens when Boba Fett plays with each kitten, and it's just the cutest thing you've ever seen.  Almost brings a tear to your eye:

image

greedo Greedo is also a noble bounty hunter, but he has a dark secret: he just loves fuzzy, adorable kittens!  He's so excited when he sees what Boba Fett got that he completely forgets about the Strategy Pattern!  Oh no!  Greedo beware!  While Greedo is distracted, Han has slipped the barkeep a bribe along with another group of "fuzzy animals":

   1: internal class Program
   2: {
   3:     private static Cantina _cantina;
   4:  
   5:     private static void Main(string[] args)
   6:     {
   7:         _cantina = new Cantina();
   8:  
   9:         GetANewPatron("Boba Fett");
  10:  
  11:         _cantina.AcceptBribe(200);
  12:         _cantina.SetStuffStrategy(new ConfusionOfWeasels());
  13:         
  14:         GetANewPatron("Greedo");
  15:  
  16:         Console.Read();
  17:     }
  18:  
  19:     private static void GetANewPatron(string name)
  20:     {
  21:         ICantinaPatron patron = _cantina.GetPatron(name);
  22:         Console.WriteLine(patron.Name + " enters the cantina");
  23:         foreach (IStuff thing in patron.Basket)
  24:             Console.WriteLine(thing.DoSomething(patron));
  25:     }
  26:  
  27: }
  28:  
  29: public class Weasel : IFuzzyAnimal
  30: {
  31:     private string _name;
  32:     private string _playmate;
  33:  
  34:     public Weasel(string name)
  35:     {
  36:         _name = name;
  37:     }
  38:  
  39:     public string Name
  40:     {
  41:         get { return _name; }
  42:     }
  43:  
  44:     public string MakeNoise()
  45:     {
  46:         return
  47:             "Hi, " + _playmate + "!  My name is " + _name +
  48:             ", and I'm a weasel!  SSHHHHREEEIIIIKKKK!!!  HISSSSSSSS!!!!!";
  49:     }
  50:  
  51:     public string Play()
  52:     {
  53:         return _name + " rips " + _playmate + " a new orifice.";
  54:     }
  55:  
  56:     public string DoSomething(ICantinaPatron patron)
  57:     {
  58:         _playmate = patron.Name;
  59:         return MakeNoise() + "\r\n" + Play() + "\r\n";
  60:     }
  61: }
  62:  
  63: public class ConfusionOfWeasels : StuffStrategy
  64: {
  65:     public override void GetStuff(ICantinaPatron cantinaPatron)
  66:     {
  67:         cantinaPatron.Basket.Add(new Weasel("Lefty"));
  68:         cantinaPatron.Basket.Add(new Weasel("One Eye"));
  69:         cantinaPatron.Basket.Add(new Weasel("Sanchez"));
  70:         cantinaPatron.Basket.Add(new Weasel("Scar"));
  71:         cantinaPatron.Basket.Add(new Weasel("Ashes"));
  72:         cantinaPatron.Basket.Add(new Weasel("Blade"));
  73:         cantinaPatron.Basket.Add(new Weasel("Rainbow Dash"));
  74:     }
  75: }

What does poor Greedo get in his basket?  That's right: a really nasty confusion of weasels (that's the right term for a collection of weasels; I looked it up) named Lefty, One Eye, Sanchez, Scar, Ashes, Blade, and (oddly enough) Rainbow Dash!  Greedo flew halfway across the galaxy to bring Han back to Jabba, but instead here's what he gets for his troubles:

image

So what's the morale of this tale?  If you're a galactic bounty hunter and you ever find yourself in a desert planet cantina that's giving away baskets of fuzzy animals, be super careful, because what you think is gonna be a litter of kittens might just turn out to be a confusion of weasels.  And, oh yeah, the Strategy Pattern is a good way to achieve some nice decoupling in your design.  But seriously, don't forget about the weasel part.

Share this post :