ArticleS
.
UncleBob
.
AbstractFactoryDanielT
Edit Page:
!title 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 #----- Blog Comment Marker (Please don't delete me) -----# !* 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. *!
Hints:
Use alt+s (Windows) or control+s (Mac OS X) to save your changes. Or, tab from the text area to the "Save" button!
Grab the lower-right corner of the text area to increase its size (works with some browsers).