SitePoint Sponsor

User Tag List

Results 1 to 4 of 4

Hybrid View

  1. #1
    Patience... bronze trophy solidcodes's Avatar
    Join Date
    Jul 2006
    Location
    Philippines
    Posts
    933
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    The best time to use Factory Pattern?

    Okay it says.
    Factory pattern says it will create object for you.
    An example of factory pattern codes,
    Code:
    <?php
    interface IUser
    {
      function getName();
    }
    
    class User implements IUser
    {
      public static function Load( $id ) 
      {
            return new User( $id );
      }
    
      public static function Create( ) 
      {
            return new User( null );
      }
    
      public function __construct( $id ) { }
    
      public function getName()
      {
        return "Jack";
      }
    }
    
    $uo = User::Load( 1 );
    echo( $uo->getName()."\n" );
    ?>
    So when is the best time to use Factory Pattern.
    And can you guys give sample scenario.

    Thank you very much in advanced.
    Quality codes are optimized and tested...
    Click here for inspiration..

  2. #2
    SitePoint Guru bronze trophy TomB's Avatar
    Join Date
    Oct 2005
    Location
    Milton Keynes, UK
    Posts
    988
    Mentioned
    9 Post(s)
    Tagged
    2 Thread(s)
    Firstly, using static methods as factories is self defeating.

    One of the reasons for using factories is polymorphism. As soon as you call "User::load()" that flexibility is lost. If you replace that with " $factory->load() " then you have added flexibility, because $factory can be an instance of anything, not necessarily an instance of the User class. Also, grouping the object creation and the object implementation is a poor separation of concerns. A better method is this:

    PHP Code:


    class UserFactory {
        public function 
    load($id) {
            return new 
    User($id);
        }
    }


    class 
    User implements IUser {
        public function 
    getName() {
            return 
    $this->name;
        }
    }



    $uo $factory->load(1); 

    This way, the code using the factory isn't tightly coupled to the factory itself, $factory can be an instance of anything.


    When should you use the factory? If you're using the factory method you'd use the factory everywhere you'd normally call "new User".

    This is because it keeps all object initialisation logic in one place. Imagine this:

    PHP Code:
    if ($_SESSION['Admin'] == true) return new AdminUser($id);
    else return new 
    User($id); 
    If that logic changes, say we add a "ModeratorUser" type, then the logic only needs to be updated in the factory. Everywhere that's creating users will remain unchanged and just call $factory->load($id);

  3. #3
    SitePoint Enthusiast
    Join Date
    Feb 2007
    Posts
    51
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    I'm using factory() in my ORM models all the time so I can chain methods in one line, e.g. $users = User::factory()->where('column', 'value')->limit(5)->get();

    Without it I would always need to use at least 2 lines:

    PHP Code:
    $users = new User();
    $users->where('column''value')->limit(5)->get(); 

  4. #4
    SitePoint Member
    Join Date
    Feb 2009
    Posts
    17
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A point can be made that static creation methods can be used in place of the new keyword( by making the constructor private ) to allow greater clarity on creation. Basically named constructors.

    eg.
    http://www.industriallogic.com/xp/re...rCreation.html
    (more in depth http://www.informit.com/articles/article.aspx?p=1398606 )
    http://c2.com/cgi/wiki?FactoryMethodPattern
    http://c2.com/cgi/wiki?CreationMethod

    Php is slight different as it does not have overloading but named constructors can help by removing the need for default values be part of public api and confer what the construction means. Say for a response from a service instead of a boolean and a requirement to call other accessor to get the error out( quite boring to test and far less useful to return further back through the call chain ).

    PHP Code:
    <?php

    class Response {
        
    /**
         * @var bool
         */
        
    private $isSuccessful;

        
    /**
         * @var string
         */
        
    private $errorMessage;


        
    /**
         * @param boolean $isSuccessful
         * @param string  $errorMessage
         */
        
    private function __construct$isSuccessful$errorMessage ) {
            
    $this->isSuccessful $isSuccessful;
            
    $this->errorMessage $errorMessage;
        }


        
    /**
         * @return Response
         */
        
    public static function createSuccess() {
            return new 
    selftrue'' );
        }


        
    /**
         * @param string $errorMessage
         *
         * @return Response
         */
        
    public static function createError$errorMessage ) {
            return new 
    selffalse$errorMessage );
        }


        
    /**
         * @return boolean
         */
        
    public function getIsSuccessful() {
            return 
    $this->isSuccessful;
        }


        
    /**
         * @return string
         */
        
    public function getErrorMessage() {
            return 
    $this->errorMessage;
        }
    }



    Or to allow the use of classes as constant values that can be passed safely at run time which have a guaranteed limited prevalidated set of values so do not need continual revalidating through the next steps in the call chain. eg.

    PHP Code:
    class BloodGroup{
        
    /**
         * @var string
         */
        
    private $bloodGroup;


        private function 
    __construct$bloodGroup ) {
            
    $this->bloodGroup $bloodGroup;
        }

        public static function 
    A(){
            return new 
    self('A');
        }


        public static function 
    B(){
            return new 
    self('B');
        }


        public static function 
    O(){
            return new 
    self('O');
        }


        public static function 
    AB(){
            return new 
    self('AB');
        }


        
    /**
         * @param int $type -- comes from database
         *
         * @throws Exception
         * @return \BloodGroup
         */
        
    public static function createFromType$type ) {
            switch( 
    $type ){
                case 
    1:
                    return 
    self::A();

                case 
    2:
                    return 
    self::B();

                case 
    3:
                    return 
    self::O();

                case 
    4:
                    return 
    self::AB();
            }

            throw new 
    Exception'type ' $type 'is an unrecognised type' );
        }


        function 
    __toString() {
            return 
    $this->bloodGroup;
        }

    This example draws paralells to
    http://sourcemaking.com/refactoring/...ode-with-class and sometimes a later refactoring moves to replace type code with subclasses if further behaviour is required across the values. These may look similar to usual factories but it is a technique to remove primitives and allow small pieces of self validating behaviour to be put in their place.

    These techniques are not used very often as they are quite small but can prove very useful as they are for the direct replacement of the new keyword. The first for clarity when an order of parameters means something in human terms, the second for flexibility in future refactoring and also the safety as it can be type hinted and trusted to behave accordingly without further checks from outside wherever it is passed.

    Sometimes factory method and creation method are used interchangeably which can obscure it.

    Tom is right that that factories are far more useful when injectable than static due to the mocking it allows and interchangeability using polymorhpism ). These examples are usually asserted against as a result from a method call.

    eg.

    PHP Code:
    $this->assertEqualsResponse::createError('problem'), $testClass->testCall('failing value'); 


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •