1

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(); } 
6
  • the second way has less code, and is better. why create multiple ways to set First Name ? Commented Dec 28, 2011 at 22:46
  • As per @mmmshuddup 's answer, I don't believe that this is actually the factory pattern. Commented Dec 28, 2011 at 22:59
  • en.wikipedia.org/wiki/Factory_method_pattern Commented Dec 28, 2011 at 22:59
  • "Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses." quoted from the gang of four Commented Dec 28, 2011 at 23:00
  • I also think #2 is a better way, cause the model itself describe what we try to define... plus it's easier when you have to deal with collection properties like address. I also like the second one cause you know exactly what property you can define without the need to look at the documentation of the function. Important thing you don't have to count params to understand what is param 7 mean. Ex: create('Yanik', 'Lupien', 8, '2011-12-28', false, true, 8); But I read some DDD books that tell factory should return valid instance. That's why I ask what it the best way to do it. Commented Dec 28, 2011 at 23:12

2 Answers 2

3

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'); 
Sign up to request clarification or add additional context in comments.

5 Comments

"Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses." en.wikipedia.org/wiki/Factory_method_pattern#cite_ref-0
The thing with $options array is there is no interface that I can work with. An array can contain everything and nothing with any kind of typed value. To know what can I give to this create method I should have to dig in code and try to understand what I can define. In contrast, class define a nice signature where I can speak and know exactly what I can do with it. If you work a User class you know you can assign firstName..
@YanikLupien Yes, you are correct. I was just simply trying to demonstrate to the OP alternate methods of getting something done with less code. You're right though, you can't "interface" the array, which could be problematic if, say, the array had many elements. I, personally, use an $options array whenever I know for a fact that I will only need a few things to set in it.
I think if you specify user type it's a good reason to have a param in the create method of the factory. And finally to assign member specific to each type we can probably use if ($user instanceof UserSuperAdmin) { $user->defineUserAdminProperties(); } ...
The static method is hard to unit test - what is wrong with factory class?
1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.