Builders and factories and objects, oh my!

(I wrote this about three weeks ago and never got a chance to post it. Luckily there's a small lull before I head over to CeBit later this week so I thought I should finish it)

After you've been developing test-first for a while (six months+ ?), you start to sense when something is wrong with your code. In my case, I tend to refactor a lot more now and when classes start to grow in size I start to get an uneasy feeling. Normally my tests examples will drive out a better design, but in this case I'm working on a view-style class: all it does is generate images.

This isn't to say it wasn't developed test-first just like everything else, but there is little to do apart from verifying properties and checking that the returned Bitmap isn't null. Originally this Factory class had a dependency on one other class that generated the points for the graph it needed to draw. Feature-creep being what it is, I've now got three extra parameters coming into my Create() method and things are starting to get messy.

 internal class GanttBarFactory
{
  // ...
  // Constructor and some properties
  // ...

  public Bitmap Create(int height, int dayWidth, ... )
  {
    TrendToPointsConvertor convertor = new ....

    Bitmap image = new Bitmap(convertor.Width, height);
    Graphics g = Graphics.FromImage(image);

    DrawFillAndOutline(g, ...);
    DrawTrends(g, ...);
    DrawTopBar(g, ...);
  }
}

I had already done some extraction to get the three DrawXXX() methods, but they in turn call other private methods. If this were a "regular" class, I'm sure I'd already have refactored to a better design.

There are now five private methods which should all be static and then it hits meā€”this class isn't a factory anymore! Now, it was never a "real" factory in the GOF sense, but it did create a Bitmap based on data from another class. The other class couldn't generate the bitmap itself as that would break the single-responsibility principle and Just Be Wrong.

The introduction of the extra parameters to Create changed how the class worked: instead of creating a bitmap, it was now assembling a bitmap and so we have a builder rather than a factory. No great revelations here; it just struck me that had I not been so used to refactoring thanks to TDD, I might have just left this as-is. I'll chalk it up to part of growing as a developer :)

As a side note, I'm hoping to get the time to write about some more interesting subjects like Dependency Injection and AOP. Now that Enterprise Library handles cross-cutting concerns (which Brad and Scott have already posted about), I want to play around with it a bit. (The alternative was to start digging into Spring.NET) I was trying to explain to a co-worker of mine why anyone would to use CAB and I think blogging about that entire domain may give me some nice examples.

Comments

  • Anonymous
    May 08, 2007
    Actually, I was in <Lithe> for a while, but I haven't played WoW in a good long time. I just came