PHP Tutorial: The Allegory of The Factory Pattern
| June 12, 2012 | Posted by Greg Bulmash under PHP |
If you've read the About This Site page, you'll know that instead of pursuing my passion for computers, I got sidetracked into the arts in college. So when it came time for me to learn and explain the Factory Pattern, I thought it might be fun to express it as an allegory...
Henry had a company that made these new fangled things called automobiles. Now automobiles were made up of a lot of parts, and one of the primary parts they needed was axles. Each axle needed to implement two methods:
attachWheels()andturn().Steven had a company that made axles. He supplied axles to Henry's assembly line. When Henry first designed his automobile, he thought an axle from a solid piece of hickory would do a really good job. So he printed up a bunch of ordering forms that specified
new HickoryWoodAxle()as the part to be used.One day, over drinks at the country club, Steven was talking with Andrew. Andrew told him "I can supply you with birch at half the cost of hickory and it will be just as strong." Knowing it would be wrong to change the wood without approval, Steven called Henry, who was busy trying to hit rubber frogs into a copper spitoon with a croquet mallet. "Yeah, yeah, whatever," Henry said.
Steven went into production immediately, making axles out of birch. Feeling it would be dishonest to call them
HickoryWoodAxle(), he changed the part ID toBirchWoodAxle(). Henry, however, had caught a ship to Bora Bora where he was under the delusion that he was headlining a three-act musical tribute to molybdenum in the basement of an opium den, and forgot to inform his plant to change the order form.The next time Henry's plant requested a
HickoryWoodAxle(), the shipping manager at Steven's plant looked in inventory and said "we don't have any of those." He refused to send Henry's plant aHickoryWoodAxle(), and Henry's plant had to shut down. If only they'd known to order aBirchWoodAxle(), they could have kept production plugging along.Henry's stockholders met in secret and sent a team of elite Jesuit ninjas to extract Henry from the steppes of Mongolia where he'd become the alpha male in a herd of Yak. When he got back, he called Steven and chewed him out. Steven argued back that Henry should have told his procurement staff of the change. The argument got so heated that they met and had a forty-seven-hour thumb wrestling competition to settle it, but that ended in a draw.
Still, during that competition, they got to talking. "Why does it have to be so difficult," Henry asked. "All I want is an axle. All it has to do is
attachWheels()andturn(). I don't care what material you use."As their thumbs darted back and forth in an intricate dance better explained by a color commentator, their lawyers drew up a contract, defining how Steven and Henry would interface. At Steven's factory, if they got in an order for a
new axle(), so long as it couldattachWheels()andturn(), that would be good enough. And that way Steven could change his tooling, his materials, or even ship the production overseas. So long as Henry got anaxle()that behaved as expected, he'd be happy.
So the Factory pattern, as I understand it, is one of the most basic implementations of Loose Coupling. That's where too much knowledge is a dangerous thing. Through the order forms, Henry's assembly line was coded to request a HickoryWoodAxle() object. Every time Steven's plant changed the material, and thus the name of the product class, Henry's assembly line would have to change its order form or the whole system could break down.
So they negotiated an interface...
interface IAxle {
function attachWheels();
function turn();
}
Using that interface as a guide, Steven could create his axle factory that would send an Axle, every time someone sent it a buy order.
class Axle implements IAxle {
private $_material = "ceramic";
public function attachWheels(){
return "Wheels attached";
}
public function turn(){
return "Turning";
}
public static function buy(){
return new Axle();
}
}
Then all you'd need to do is buy an Axle and you can attach Wheels or set it turning.
$axle = Axle::buy();
echo "{$axle->attachWheels()}<br>";
echo "{$axle->turn()}<br>";
And there you have it. If you like my idea of pattern allegories, please speak up in the comments. It will encourage me to do more. If you don't, then you're a philistine.
I loved this allegory - it finally makes sense. Nice job and I'd like to see more!
Thanks for explaining this pattern.
I wonder, shouldn't the buy() function be a static function?
Actually, the code worked as expected with public on my dev system, but you're right that the best practice would be to declare the method as static. Changed.
Great post, really makes fun reading this and this way it is easy to understand for everyone.
Actually, what you've described is really just inheritance.
How you get an instance -- not necessarily whether or not it it implements one or more interfaces is what the factory pattern is about.
A good extension of the allegory that describes a factory pattern would be specifying that the axle procurement process always returns a HickoryWoodAxle when Henry Ford asks for an Axle to make sure no BirchWoodAxle with inferior tensile strength is used in Ford's factories.
class AxleFactory { /** * @param Material substance used to create an axle * @return Axle - an implementation */ public static function createAxle($material) { if ($material == MATERIALS_HICKORY) { return new HickoryWoodAxle(); } else { return new BirchWoodAxle(); } } }Now Henry can specify what type of material he wants his axles to be made on the procurement form and Steven can be sure to fulfill the order exactly as he specifies. If he doesn't specify, Steven is free to send Henry whatever type Axle he wants (as long as it fulfills the IAxle contract.)
This is great! Not sure why there aren't more allegories when describing such abstract concepts like OOP.
Is this really the factory pattern?
My understanding is that a factory pattern returns a specific type of object depending on how it is instantiated by client code. Your code better demonstrates how to implement an interface than it does implementing a factory pattern.
Would a more concrete example of a factory pattern allow for the client code to pass in the material value and have your Axle class return a different object based on material?