Hi, I've been coding for a long time now but never got my hands on using patterns. Now finally we're putting together our own MVC framework and are implementing certain patterns. Due to our high level of traffic and many stages of development we have many many configuration settings that are traditionally solved by a simple if and some config files. Being strict to a MVC method and maintaining a strict OO development we are now loading our config via a Config Class which works great when only a single set of configs are needed. Though when we need to load different Configurations depending on server environment we want to override config class and its values. Currently we're considering this could be done using Observer Patterns where we detect which environment we're in and we override the Config Class with new corresponding values. Is this the best way to do this? Or are we just overdoing this? Any feedback highly appreciated.
You can't use a simple factory to choose the right Config class? How were you going to use the observer pattern, by making the main config class observable? I think observer is most useful with event based problems. This doesn't strike me as a good fit, but maybe if I saw the solution I'd change my mind.
thanks for the reply.. i'm still very new to patterns and not too sure how the factory pattern actually works.. but will have a look into it. answering your question: yes, i was thinking of making the config class observable.. does it make sense? i've read that observable is best suited for events and that's why i was not 100% convinced on using this pattern..
class PAGE{ public $menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); //continue code here............. }//end PAGE class class MEMBER extends PAGE{ public $menu = array( //<---this is the overloading of page menu to a new menu 'Member' => 'member.php', 'Login' => 'login.php', 'Register' => 'register.php' ); //continue code here............. }//end MEMBER class PHP:
Yeah, I don't think the observer makes sense here at all.(Just my opinion and I'm not really an expert on patterns) If you're not worried about PHP4 compatibility you can create an abstract class or interface and from that you can creat different implementations of your config class. Or you can just be less formal about it and not create a formal "contract". class Config { var $main = array(); function DevConfig() { ; } // if you're not worried about running on PHP4 then put "abstract" before the word function. // example: abstract function getAll() // If you do this you may have to put the "abstract" keyword in front of the "class Config" above as well. function getAll() { die(__METHOD__.' is abstract, must implement in child class'); } } class DevConfig extends Config { function DevConfig() { parent::Config(); $this->menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); } getAll() { return $this->menu; } } class ProductionConfig extends Config { function ProductionConfig() { parent::Config(); $this->menu = array( //<---this is the overloading of page menu to a new menu 'Member' => 'member.php', 'Login' => 'login.php', 'Register' => 'register.php' ); } getAll() { return $this->menu; } } class ConfigFactory { function getConfig($type) { switch($type) { case 'dev': return new DevConfig; case 'production': return new ProductionConfig; } } } // You would create object like this: $myConfig = ConfigFactory::getConfig('dev'); // In this case 'dev' is the type of config class you want. You can get this value from another config or bootstrap file if you want. PHP: I pretty much took the example from here http://en.wikipedia.org/wiki/Factory_method_pattern and changed it to fit your needs. In the example code the method that actually creates and returns the object looks like this: public static ImageReader getImageReader( InputStream is ) { int imageType = figureOutImageType( is ); switch( imageType ) { case ImageReaderFactory.GIF: return new GifReader( is ); case ImageReaderFactory.JPEG: return new JpegReader( is ); // etc. } } } Code (markup): The main difference is that in the ImageReader example you're passing in an object that is examined and then the proper object is automatically returned. You often have to pass something in to give the factory a hint of what to return. The ImageReader better encapsulates the creation process because your client code(the code that calls the factory) doesn't have to figure out anything on its own, it just passes in an image. You could maybe achieve better encapsulation by just letting your config factory figure out which object to return on its own. But how it does that really depends on the situation. But to be honest, after looking at things again, I'm not even sure this should be called a config class. Also, remember that patterns are different from implementations. Patterns just provide general guidelines on how to solve a problem. So for example when you read about the factory pattern from the link above, you don't have to do it exactly that way.
The purpose of the code I posted was a bit unclear. It seems what you really want is different menus based on condition, so I've edited things a bit here. <?php class PageMenu { var $main = array(); function PageMenu () { ; } // if you're not worried about running on PHP4 then put "abstract" before the word function. // example: abstract function getAll() // If you do this you may have to put the "abstract" keyword in front of the "class Config" above as well. function getAll() { die(__METHOD__.' is abstract, must implement in child class'); } } class MemberMenu extends PageMenu { function MemberMenu() { parent::PageMenu(); $this->menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); } getAll() { return $this->menu; } } class MenuFactory { function get($type) { switch($type) { case 'member': return new MemberMenu; case 'page': return new PageMenu; } } } // You would create object like this: $myConfig = MenuFactory::get('member'); ?> PHP:
Hi, Yes you right, my code is not a better example of pattern but that code shows how you overload your base properties and methods. That overloading example is work perfect and I'm using it in all my web project. class PAGE{ public $menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); //continue code here............. }//end PAGE class class MEMBER extends PAGE{ public $menu = array( //<---this is the overloading of page menu to a new menu 'Member' => 'member.php', 'Login' => 'login.php', 'Register' => 'register.php' ); //continue code here............. }//end MEMBER class PHP:
function MemberMenu() { parent::PageMenu(); //<--- you don't need this line. You already extends the base class and you can access to their public properties and methods. $this->menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); } PHP: Oh and one more thing, You only use abstract if you don't need to instantiated a class object.
The reason I included the reference to abstract is because when you have a problem that warrants creating a factory, then it usually also warrants creating a strong interface for a set of related objects. Which means you should probably create a general abstract superclass or interface that all of the other objects that the factory will make will derive from or implement. One of the goals of a factory should be to create objects with almost identical interfaces and external behaviour. So creating an abstract superclass is one way to solidify and give coherency to the interfaces of the objects that the factory will be creating. An abstract class could work as a "blueprint" that states that this factory will create objects from classes that all look something like this abstract class. If I were going to do this "correctly", I would probably create an abstract Menu superclass and have PageMenu(although I'd probably try to find another name for PageMenu, that's not very descriptive) and MemberMenu extend it. The superclass would be a good place to call/run code that is common to all subclasses so while a call to the parent constructor may not be needed now, it may be need in the future.
Here's an example that shows two menu classes extending an abstract class. It hopes to show the purpose of an abstract class and why to call the constructor in the subclasses. This is strictly PHP5 syntax which I was trying to avoid in my previous examples. <?php abstract class Menu { protected $menu = array(); public function __construct() { $this->setupMenu(); } public function getAll() { return $this->menu; } abstract protected function setupMenu(); } class PageMenu extends Menu { public function __construct() { parent::__construct(); } protected function setupMenu() { $this->menu = array( 'Home' => 'home.php', 'Contact Us' => 'contact.php', 'About Us' => 'about.php' ); } } class MemberMenu extends Menu { public function __construct() { parent::__construct(); } protected function setupMenu() { $this->menu = array( 'Member' => 'member.php', 'Login' => 'login.php', 'Register' => 'register.php' ); } } class MenuFactory { public static function get($type) { switch($type) { case 'member': return new MemberMenu; case 'page': return new PageMenu; } } } // You would create object like this: $myConfig = MenuFactory::get('member'); var_dump($myConfig); ?> PHP: