Yanik Lupien
Yanik Lupien

Reputation: 120

Which is the best way to implement factory method

Which is the best way to implement factory method.

1) A factory method that contain all members of the model to define

class UserFactory {
    /**
     * @return UserModel
     */
    function create($firstName, $lastName, $age) {
       $user = new UserModel();
       $user->setFirstName($firstName);
       $user->setLastName($firstName);
       $user->setAge($age);
       return $user;
    }
}

// Usage example
$user = $userFactory->createUser('Yanik', 'Lupien', 99);
$userRepo->persist($user);

2) A factory method that simply create the model and return it. After we can fill the model by using the model setters.

class UserFactory {
    /**
     * @return UserModel
     */
    function create() {
       $user = new UserModel();
       return $user;
    } 
}

// Usage example
$user = $userFactory->create();
$user->setFirstName('Yanik');
$user->setLastName('Lupien');
$user->setAge(99);

$userRepo->persist($user);

3) A Factory that return a different class implementation base on a param

class MyUserFactory {

    const ADMIN = 'admin';
    const SUPER_ADMIN = 'superadmin';

    public function create($type = self::ADMIN)
    {
    switch ($type) {
    case self::SUPER_ADMIN:
        return new UserSuperAdmin($options);
        break;

    case self::ADMIN:
    default:
        return new UserAdmin($options);
        break;
    }
}

// Usage 
$user = $myUserFactory->create(MyUserFactory::SUPER_ADMIN);

if ($user instanceof UserSuperAdmin) {
   $user->setSuperAdminProperties();
}

if ($user instanceof UserAdmin) {
   $user->setAdminProperties();
}

Upvotes: 1

Views: 228

Answers (2)

Yes Barry
Yes Barry

Reputation: 9876

The way I've always seen the factory pattern applied is when there are multiple types of, say, users. For example, admin and superadmin. You could have a factory method like so:

// within a class named "User" for example
const ADMIN = 'admin';
const SUPER_ADMIN = 'superadmin';

// ...

public static function factory($type = 'admin')
{
    switch ($type) {
        case self::SUPER_ADMIN:
            return new UserSuperAdmin();
            break;

        case self::ADMIN:
        default:
            return new UserAdmin();
            break;
    }
}

Both - or ANY for that matter - of the User classes would implement some sort of interface that defines those getters and setters you were using like setFirstName() and setAge() for example.

You could also define an $options array or something to pass along to each of their constructors to instantiate all of those fields right away for you.

public static function factory($type = 'admin', $options = array())
{
    switch ($type) {
        case self::SUPER_ADMIN:
            return new UserSuperAdmin($options);
            break;

        case self::ADMIN:
        default:
            return new UserAdmin($options);
            break;
    }
}

Then, here is an example of one of the contructors:

class UserAdmin implements IUserInterface // for example
{
    public function __construct($options)
    {
        // do something with the options array
    }
}

Then when you instantiate it, it's as simple as something like this:

$user = User::factory('admin');

Upvotes: 3

ChristopherS
ChristopherS

Reputation: 883

You are the only person who can decide this. You should consider the following options:

  1. Will your user instance always require the same kind of input in the constructor? Then it's a good choice to pass them to the factory method.
  2. Does the returned instance depend on the kind of user you need to instantiate? If it does you will have to pass the correct parameters to the factory so it can decide for you. It's important to look in the near future what you will need. Don't pass too much or too little.
  3. You can create a dto (data transfer object) class to define all properties of a user. This way, you can pass a lot of information to the factory method and it might be more bullet proof for the future (like roles, permissions, etc).
  4. Some people might say to just pass all the information you have to the factory method so all logic can be performed by the factory method, even if it isn't required right now.

Upvotes: 1

Related Questions