The problem:
We need a method that could generate us different “products” based on different conditions or, why not, depending on the context. If we didn’t know about design patterns we would solve this by creating an endless if then else set of conditions. I know, this is the fastest solution that comes into your head, but have you ever think of the consequences of this practice? What will you do when you will have to add some other conditions? We need some automation of this process.
Here comes the Factory Pattern, a creational design pattern, which consists (or make use) of the Abstract Factory Pattern and the Factory Method Pattern. Let’s see what’s the role of every each of this two:
- Abstract Factory Pattern centralize decision of what factory ( = the thing that generates us “products”) to instantiate.
- Factory Method Pattern centralize creation of an object of a specific type choosing one of several implementations
Factory pattern is usually used in framework’s libraries design, where appears the need to create objects of types which may be subclassed by applications using the framework.
Oh, a lot of theoretical terms, ah? Let’s skip this and go ahead with the implementation. Think about some items, which can be video items, photo items or image items, for now. Depending on the type, there should be a different handling of the items. Knowing the problem we should find a solution and the first one is a simple procedural check on the type of the item and then continue with coding. This is rather tricky because we should perform this check every time we handle items. Using object oriented code and the factory pattern we get rid of this “every time check” and let the factory’s products to handle this job.
The solution (implementation):
Example for procedural mode:
//index.php – display items We assume that we have in $items a list of items. foreach($items as $key=>$item){ if($item[‘type’] == ‘video’){ display_video_item($item[‘id’]); } elseif($item[‘type’] == ‘audio’){ display_audio_item($item[‘id’]); } elseif($item[‘type’] == ‘photo’){ display_photo_item($item[‘id’]); } //I’ve use a conditional statement to iterate through all items’s types } //display the number of items …… if($item[‘type’] == ‘video’){ echo count_video_items(); } elseif($item[‘type’] == ‘audio’){ echo count_audio_items(); } elseif($item[‘type’] == ‘photo’){ echo count_photo_items(); }
And these are only two situations where we need some kind of classification based on item type. What should we do when somebody ask us to add a text item type, or to split photo item type into other categories ….
Example for object oriented mode:
Well, we know that we have 3 item types: video, audio and photo, so … we can develop 3 classes and why not make use of the abstract factory too.
abstract class Item{ public function countItems(){ $count = 0; //get number of items of some type and put it in $count return $count; } public function displayItems(){ //get items of some type and display them } } //here we can add what ever validations and methods (related to the working type) that we want (this classes inherits all the methods of Item class) class VideoItem extends Item{ public function getTitle($id = 0){ //get the title of the item with ID = $id } } class AudioItem extends Item{ public function getDescription($id = 0){ //get the description of the item with ID = $id } } class PhotoItem extends Item{} class ItemFactory{ public static function createItem($type){ $baseClass = 'Item'; $targetClass = ucfirst($type).$baseClass; if (class_exists($targetClass) && is_subclass_of($targetClass, $baseClass)) return new $targetClass; else throw new Exception("Item type '$type' is not recognized."); } } $types = array(‘video’, ‘audio’, ‘photo’); foreach($types as $key=>$type){ ItemFactory::createItem($type)->displayItems(); ItemFactory::createItem($type)->countItems(); }
You can notice that this is an elegant solution indeed. Also, you can ask yourself why to use so many classes to do that. Well, the answer is very simple, these classes can be used in other application with a slight of modification.
Related posts: