[oop] factory vs constructor
In een ander topic zegt Wouter op een gegeven moment:
Wouter J op 02/03/2014 16:08:06:
allereerst zou ik geen setters gebruiken voor id en value. Dat zijn verplichte waarden, geef die dus mee aan de constructor en nog mooier: gebruik een factory: Session::create('user', 'Ozzie')
Waarom zou je een factory gebruiken ipv een constructor?
Waarom...
en niet...
Wat is het verschil/voordeel?
Als je beginner bent dan adviseer ik je altijd eenvoudig te programmeren.
Gebruik Object-oriented concept en namespace die zijn belangrijk.
Factory design is echt niet dat belangrijk voor een beginner.
Factory design is gebaseerd op een eenvoudig princiep.
Net als een fabriek dat maakt verschillen producten.
Het kan een global fabriek of meerder sub fabrieken.
Dus een factory is een class dat bestaat uit meerder static methoden die creëren objecten en geven die objecten terug.
Bijv.
$Session = $Factory::creatSession('user', 'Ozzie');
$Auto = $Factory::creatProduct( ‘auto’);
….
Het kan ook heel global zijn
$Session = $Factory::creat('user', 'Ozzie');
$Auto = $Factory::creat( ‘auto’);
P.S
$session = Session::create('user', 'Ozzie');
respecteert niet de Factory design.
Gewijzigd op 07/03/2014 19:25:17 door Simo Mr
$session = Session::create('user', 'Ozzie');
respecteert niet de Factory design.
Maar dat is dus ook mijn vraag...
Waarom zou je dit doen
$session = Session::create('user', 'Ozzie')
in plaats van dit?
$session = new Session('user', 'Ozzie');
Hier is een simpel voorbeeld zonder factory design.
Code (php)
1
2
3
4
5
2
3
4
5
if (class_exists('auto') && class_exists('motor') && class_exists('wielen') ) {
$wielen= new wielen();
$motor= new motor();
$auto = new auto($motor, $wielen);
}
$wielen= new wielen();
$motor= new motor();
$auto = new auto($motor, $wielen);
}
met factory design
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
public static function creat($nameObject) {
if($nameObject=='auto') $this->creatAuto();
}
private function creatAuto() {
if (class_exists('auto') && class_exists('motor') && class_exists('wielen') ) {
$wielen= new wielen();
$motor= new motor();
return new auto($motor, $wielen);
} else {
die('fatal error, class not exist ');
}
}
if($nameObject=='auto') $this->creatAuto();
}
private function creatAuto() {
if (class_exists('auto') && class_exists('motor') && class_exists('wielen') ) {
$wielen= new wielen();
$motor= new motor();
return new auto($motor, $wielen);
} else {
die('fatal error, class not exist ');
}
}
Gewijzigd op 07/03/2014 19:51:06 door Simo Mr
Wat betreft jouw voorbeeld... als je een autoloader gebruikt heb je zoiets toch niet nodig?
Ik dacht dat factory's vooral bedoeld waren om een object te maken met een bepaalde configuratie, zodat je dat niet telkens hoeft te herhalen.
Toevoeging op 07/03/2014 19:57:08:
Ja! je kan dat met een autoloder gebruiken.
de bedoeling van factory is dat je alle soort objecten met een object can maken.
Toevoeging op 07/03/2014 20:01:29:
Hier is een uitleg met een voorbeeld.
http://www.phptherightway.com/pages/Design-Patterns.html
Gewijzigd op 07/03/2014 20:05:49 door Simo Mr
Code (php)
En dan...
Wat is het verschil als ik gewoon dit doe:
Ik zie het nut niet zo eigenlijk.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
final class Model {
private static $factories = array();
public static function create($model, ...$params) // PHP 5.6 variadics
{
$model = strtolower($model);
if ( ! isset(self::$factories[$model]))
throw new InvalidArgumentException('no factory found');
$factory = self::$factories[$model];
return $factory::create(...$params); // PHP 5.6 variadics
}
public static function register($model, $factory)
{
if ( ! is_string($factory) || ! method_exists($factory, 'create'))
throw new InvalidArgumentException('invalid factory');
self::$factories[strtolower($model)] = $factory;
}
}
// use namespace statements
Model::register('User', User::class);
Model::register('Profile', Profile::class);
Model::register('Game', Game::class);
// ander bestand
$user = Model::create('User', 42, 'Darsstar');
?>
final class Model {
private static $factories = array();
public static function create($model, ...$params) // PHP 5.6 variadics
{
$model = strtolower($model);
if ( ! isset(self::$factories[$model]))
throw new InvalidArgumentException('no factory found');
$factory = self::$factories[$model];
return $factory::create(...$params); // PHP 5.6 variadics
}
public static function register($model, $factory)
{
if ( ! is_string($factory) || ! method_exists($factory, 'create'))
throw new InvalidArgumentException('invalid factory');
self::$factories[strtolower($model)] = $factory;
}
}
// use namespace statements
Model::register('User', User::class);
Model::register('Profile', Profile::class);
Model::register('Game', Game::class);
// ander bestand
$user = Model::create('User', 42, 'Darsstar');
?>
Met een factory maak je een object aan van een onbekende class. Vaak weet je wel dat het een bepaalde interface implementeert, of een class X is of als parent heeft. Maar zeker weten welke class doe je vaak niet.
Soms het maken van een object bestaat uit veel stappen.
In plaats dat je dat herhaaldelijk doet elke keer als je een object wil maken.
Doe je dat een keer in jouw Factory class.
Gewijzigd op 07/03/2014 20:24:26 door Simo Mr
Hoe dan ook snap ik nog steeds niet waarom Wouter in het genoemde voorbeeld een factory "mooier" noemt, want in het betreffende geval zie ik geen meerwaarde ten opzichte van het aanmaken van een object en het meegeven van de argumenten aan de constructor.
Toevoeging op 07/03/2014 20:26:39:
>> Soms het maken van een object bestaat uit veel stappen.
In plaats dat je dat herhaaldelijk doet elke keer als je een object wil maken.
Doe je dat een keer in jouw Factory class.
Ja, maar in het voorbeeld wat Wouter geeft, is dit toch niet van toepassing?
Maar dat voegt in dit geval toch niks toe ten opzichte van $session = new Session('user', 'Ozzie') ? Of zie ik iets over het hoofd?
De constrictor van Session create een nieuwe session voor de gebruiker Ozzie.
Als die session al bestaat dan kan je beter dat checken met die static functie voor dat je helemaal een ojbect gaan creëren en opnieuw die session gaan initialiseren.
$session = new Session('user', 'Ozzie') creëert altijd een object.
$session = $Factory::creat('user', 'Ozzie'); check of dat session al bestaat als niet creëert een new.
Nu wordt het vreemd. Jij zegt dus dat een factory een bestaand object teruggeeft als dat object al bestaat?
Als je al een session geïnitialiseerd hebt dan waarom ga je dat opnieuw starten!.
De session wordt niet opnieuw gestart. Het zijn losse key->value paren waar een class omheen wordt gebouwd. Waarom weet ik overigens ook niet.
Factories bestaan er in 2 smaken:
- Factory class
- Factory method
In het geval van een klasse heb je een bepaalde klasse, 1 per object type, die weet hoe hij iets aanmaakt:
In dit geval is het gebruik van een Factory class alleen maar duidelijk, een auto maakt zichzelf niet, de fabriek maakt de auto. In de meeste gevallen is dit echter een beetje overdone, dan is een Factory method genoeg.
Het Factory Method pattern gebruik ik echter wel veel. Wat we hierboven in de code voor problemen hebben:
- Strict genomen create ik geen auto, ik assemble een auto. Tyres en Engines manufacture ik.
- We hebben nu 1 object: Tyres die voor alle soorten banden werkt. Beter is hier bepaalde kwaliteiten van een band in te stellen doormiddel van het Strategy pattern. Zelfde geldt voor de motor.
Een mooiere code zou dan zijn:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$audi = AudiManufactory::assemble(Tyres::manufacture('pirelli'), Engine::assemble('V8'));
class Tyres
{
pub static func manufacture($type)
{
$tyre = new Tyres();
switch (strtolower($type)) {
case 'pirelli':
$tyre->milesBeforeWear(2000)->...;
// ...
}
}
}
?>
$audi = AudiManufactory::assemble(Tyres::manufacture('pirelli'), Engine::assemble('V8'));
class Tyres
{
pub static func manufacture($type)
{
$tyre = new Tyres();
switch (strtolower($type)) {
case 'pirelli':
$tyre->milesBeforeWear(2000)->...;
// ...
}
}
}
?>
Wouter, maar waarom wil je in het voorbeeld met de Session class een factory gebruiken? Jij zegt omdat dat mooier is, maar waarom vind je het dan mooier?
Nou hier zie je al een duidelijk voorbeeld. Je wilt niet telkens al je initialzations aanpassen omdat je de constructor wat aanpast of omdat je wat andere waardes verwacht bij initialize. Je wilt maar 1 plek hoeven aanpassen.
Ik snap nog steeds niet wat je bedoelt eerlijk gezegd. Kun je een (pseudo) code voorbeeldje geven?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<?php
##########################
# 2014's Session.php #
##########################
class Session {
private static $request;
public static function request(Request $request = null) {
switch (func_num_args()) {
case 0:
return static::$request;
break;
case 1:
static::$request = $request;
break;
}
}
public static function create($key = FALSE, $value = FALSE) {
$args = func_get_args();
$array = array();
while (FALSE !== ($key = next($args)) && FALSE !== ($value = next($args))) {
$array[$key] = $value;
}
$session = new static(static::request());
foreach ($data as $key => $value) {
$session->set($key, $value);
}
return $session;
}
public function __construct(Request $request) {
// ...
}
}
##########################
# 2015's Session.php #
##########################
class Session {
private static $request;
public static function request(Request $request = null) {
switch (func_num_args()) {
case 0:
return static::$request;
break;
case 1:
static::$request = $request;
break;
}
}
// NEW!
private static $driver;
// NEW!
public static function driver(Session\Driver $driver = null) {
switch (func_num_args()) {
case 0:
return static::$driver;
break;
case 1:
static::$driver = $driver;
break;
}
}
public static function create($key = FALSE, $value = FALSE) {
$args = func_get_args();
$data = array();
while (FALSE !== ($key = next($args)) && FALSE !== ($value = next($args))) {
$data[$key] = $value;
}
$session = new static(static::request(), static::driver());
foreach ($data as $key => $value) {
$session->set($key, $value);
}
return $session;
}
// CHANGED!
public function __construct(Request $request, Session\Driver $driver) {
// ...
}
}
############################
# 2014's FourtyTwo.php #
############################
// Works!
$session = new Session($request);
$session->set('ford', 'prefect');
$session->set('marvin', 'the paranoid android');
// ...
// Works!
$session = Session::create('ford', 'prefect', 'marvin', 'the paranoid android');
############################
# 2015's FourtyTwo.php #
############################
// Broken!
$session = new Session($request); // error...
$session->set('ford', 'prefect');
$session->set('marvin', 'the paranoid android');
// ...
// Works!
$session = Session::create('ford', 'prefect', 'marvin', 'the paranoid android');
?>
##########################
# 2014's Session.php #
##########################
class Session {
private static $request;
public static function request(Request $request = null) {
switch (func_num_args()) {
case 0:
return static::$request;
break;
case 1:
static::$request = $request;
break;
}
}
public static function create($key = FALSE, $value = FALSE) {
$args = func_get_args();
$array = array();
while (FALSE !== ($key = next($args)) && FALSE !== ($value = next($args))) {
$array[$key] = $value;
}
$session = new static(static::request());
foreach ($data as $key => $value) {
$session->set($key, $value);
}
return $session;
}
public function __construct(Request $request) {
// ...
}
}
##########################
# 2015's Session.php #
##########################
class Session {
private static $request;
public static function request(Request $request = null) {
switch (func_num_args()) {
case 0:
return static::$request;
break;
case 1:
static::$request = $request;
break;
}
}
// NEW!
private static $driver;
// NEW!
public static function driver(Session\Driver $driver = null) {
switch (func_num_args()) {
case 0:
return static::$driver;
break;
case 1:
static::$driver = $driver;
break;
}
}
public static function create($key = FALSE, $value = FALSE) {
$args = func_get_args();
$data = array();
while (FALSE !== ($key = next($args)) && FALSE !== ($value = next($args))) {
$data[$key] = $value;
}
$session = new static(static::request(), static::driver());
foreach ($data as $key => $value) {
$session->set($key, $value);
}
return $session;
}
// CHANGED!
public function __construct(Request $request, Session\Driver $driver) {
// ...
}
}
############################
# 2014's FourtyTwo.php #
############################
// Works!
$session = new Session($request);
$session->set('ford', 'prefect');
$session->set('marvin', 'the paranoid android');
// ...
// Works!
$session = Session::create('ford', 'prefect', 'marvin', 'the paranoid android');
############################
# 2015's FourtyTwo.php #
############################
// Broken!
$session = new Session($request); // error...
$session->set('ford', 'prefect');
$session->set('marvin', 'the paranoid android');
// ...
// Works!
$session = Session::create('ford', 'prefect', 'marvin', 'the paranoid android');
?>
Gewijzigd op 08/03/2014 20:08:26 door Dos Moonen