ArticleS. UncleBob.
AbstractFactoryDanielT [add child]

Abstract Factory by Daniel T


"Daniel T." <daniel_t@earthlink.net> posted a story that I rather liked on comp.object. I have republished it here with his permission. I thought you might enjoy it.


Mike was worried, he took a sick day yesterday to get a tooth extracted
and he just knew his pair programmer John wouldn't let that stop him
from writing a bunch of code... Alone. Sure enough when he got to the
office, John was excited wanting to show Mike what was done.

"Great news!" said John, "our DSL engine has been so successful in
product A that the powers that be asked us to put it in product B as
well."

"Sounds like we have our work cut out for us," muttered Mike.

"Nope! Already done. Want to look?"

class Engine:
def __init__(self, param):
self.param = param

def elsewhere(self):
if self.param = "A":
self.preParser = PreParserA()
elif self.param = "B":
self.preParser = PreParserB()
# do some work
if self.param = "A":
self.parser = ParserA()
elif self.param = "B":
self.parser = ParserB()
# do more work

Mike groaned, "What's wrong?" said John.

"Nothing, my tooth is hurting is all... Two different if/else chains
working off of the same parameter? Can't we combine that into one at
the top?"

if self.param = "A":
self.preParser = PreParserA()
self.parser = ParserA()
elif self.param = "B":
self.preParser = PreParserB()
self.parser = ParserB()

John said, "I tried that, the user rep. said that it took too long for
the code to start parsing that way."

"I still don't like having two if/else chains, how about we make a
factory." said Mike.

"Oh no! There you go with your Design Patterns again. What's wrong with
two if/else chains?"

"We now have to support two languages, I suspect a third will be less
than a year away. So let's do this:"

class ParserFactoryA:
def createPreParser(self):
return PreParserA()

def createParser(self):
return ParserA()

class ParserFactoryB:
def createPreParser(self):
return PreParserB()

def createParser(self):
return ParserB()

#elsewhere
if self.param = "A":
self.parserFactory = ParserFactoryA()
elif self.param = "B":
self.parserFactory = ParserFactoryB()
#later
self.preParser = self.parserFactory.createPreParser()
#later still
self.parser = self.parserFactory.createParser()

"Well," said John, "I see how that will make it easer to add in a
different language in the future, but we still have that if/else chain
in the middle of our engine."

"Let's see where that 'param' variable comes from... Ah it's passed
into the constructor. How about we move the parserFactory creation
there? That will make it much easer to find when it's time to make
changes again."

class Engine:
def __init__(self, param):
if param = "A":
self.parserFactory = ParserFactoryA()
elif param = "B":
self.parserFactory = ParserFactoryB()

def elsewhere(self):
self.preParser = self.parserFactory.createPreParser()
# do some work
self.parser = self.parserFactory.createParser()
# do more work

Then John made an "idea" face. It was something he did when he got
excited... Mike learned to live with it long ago. John said, "Wait, why
are we passing in a param just to convert it into a factory object?
What if we passed in the factory object in the first place? Then it
would be part of the product where it belongs!"

Mike had to admit, it was a good idea.

class Engine:
def __init__(self, parserFactory):
self.parserFactory = parserFactory

Not only did this remove the if/else chain from the engine, but it
removed the chain completely. Each of the products would create and
pass in a ParserFactory made specifically for them.

Later, in the meeting, Mike's tooth was throbbing so he let John
explain the changes. John drew the UML on the white board and was about
to launch into a lengthy explanation when Sally said, "Oh, an Abstract
Factory. OK we can handle that."

John protested, "But I haven't explained how it works!"

"John," said Mary, "we've all studied the 'Design Patterns' book, we
understand."

"One thing about these Design Patterns," said John, "they sure do make
for shorter meetings."


!commentForm -r

 Thu, 2 Nov 2006 17:14:36, Pete, nowhere else to post
  • Any chance of fixing the style sheets for fitnesse? Resizing text in the browser makes all the fixed sizes mess up. All the screen shots in the Fit book show that the page can't be resized nicely... the scroll bar appears along the bottom of the page. If you scroll it the main text will overlap the menu.
  • Also what's happening with fitnesse.org? The recent changes are a mess.
  • Also, I think Fit, Fitnesse, the Craftsman and Michael Feathers are all great!
 Fri, 27 Oct 2006 06:33:37, Daniel T., Motivation
I wrote this story in response to the one that "Uncle Bob" recently wrote about abstract factories. I felt that his story didn't do enough to express the power of an abstract factory at (a) coordinating the production of a family of products and (b) deciding what specific type of object to produce thus removing that responsibility from the client code completely.