OOP leren
Dit snap ik wel allemaal ;)
Moet ik als class naam Product nemen?
Moet ik als class naam Product nemen?
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M
Gesponsorde koppelingen:
roel schreef op 26.08.2009 20:19:
Dit snap ik wel allemaal ;)
Maar je hebt geen poging gedaan om ook een scriptvoorbeeldje te maken. En daar gaat het om: dat je actief meedoet.
En niet afkijken! Je laten "inspireren" mag natuurlijk wel :P
Doe de oefeningen nu even, dan krijg je een beetje gevoel voor wanneer je welke methode moet gebruiken. Wanneer je moet extenden, wanneer je methods moet inzetten, waar je interfaces kan toepassen, waar je beter compositie kan toepassen, etc.
Dat beetje oefening kan geen kwaad voordat je je op je voor OOP toch redelijk lastige probleem gaat storten.
Doe de oefeningen nu even, dan krijg je een beetje gevoel voor wanneer je welke methode moet gebruiken. Wanneer je moet extenden, wanneer je methods moet inzetten, waar je interfaces kan toepassen, waar je beter compositie kan toepassen, etc.
Dat beetje oefening kan geen kwaad voordat je je op je voor OOP toch redelijk lastige probleem gaat storten.
@Jan Koehoorn
In dit geval is het zo dat: Een koe nooit kan brullen, een leeuw nooit kan loeien etc.
Dit is nu in jouw voorbeeld niet afgevangen/ af te vangen, tenzij met een hele boel extra code. Op zich snap ik wel dat je hiervoor kiest ivm herbruikbaarheid van het één en ander, maar niet waarom je dit zo doet bij jou vraagstelling.
Kan je dat evt. wat meer toelichten?
In dit geval is het zo dat: Een koe nooit kan brullen, een leeuw nooit kan loeien etc.
Dit is nu in jouw voorbeeld niet afgevangen/ af te vangen, tenzij met een hele boel extra code. Op zich snap ik wel dat je hiervoor kiest ivm herbruikbaarheid van het één en ander, maar niet waarom je dit zo doet bij jou vraagstelling.
Kan je dat evt. wat meer toelichten?
Robert_Deiman schreef op 27.08.2009 10:02:
@Jan Koehoorn
In dit geval is het zo dat: Een koe nooit kan brullen, een leeuw nooit kan loeien etc.
Dit is nu in jouw voorbeeld niet afgevangen/ af te vangen, tenzij met een hele boel extra code. Op zich snap ik wel dat je hiervoor kiest ivm herbruikbaarheid van het één en ander, maar niet waarom je dit zo doet bij jou vraagstelling.
Kan je dat evt. wat meer toelichten?
In dit geval is het zo dat: Een koe nooit kan brullen, een leeuw nooit kan loeien etc.
Dit is nu in jouw voorbeeld niet afgevangen/ af te vangen, tenzij met een hele boel extra code. Op zich snap ik wel dat je hiervoor kiest ivm herbruikbaarheid van het één en ander, maar niet waarom je dit zo doet bij jou vraagstelling.
Kan je dat evt. wat meer toelichten?
Mijn voorbeeld is natuurlijk een eerste opzet. Maar je kunt heel gemakkelijk een methode setGeluid aan de class Dier toevoegen. En dan kun je bijvoorbeeld zoiets doen:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$koe = new Koe ();
$brullen = new Brullen ();
$koe->setGeluid ($brullen);
$koe->geluid->laatHoren ();
?>
$koe = new Koe ();
$brullen = new Brullen ();
$koe->setGeluid ($brullen);
$koe->geluid->laatHoren ();
?>
Je kunt dus "at runtime" nog het "geluidgedrag" van de classe Dier aanpassen.
p.s. belangrijk is dus, dat je geen methodes gaat schrijven als:
In plaats daarvan maak je de boel abstract door en method laatHoren te schrijven. Een van de vele OOP principes is: encapsulate what varies. Elk dier kan op zijn eigen manier geluid maken, of kan misschien helemaal geen geluid maken. Vandaar dat ik een interface Geluid gebruik om het "geluidgedrag" te implementeren.
Gewijzigd op 01/01/1970 01:00:00 door Jan Koehoorn
Oké, het is me helemaal helder. Zat er wat raar tegenaan te kijken, omdat in mijn "point of view" een Dier maar 1 soort geluid maakt, jij hebt het echter een lvl omhoog getild om het OOP principe wat beter en duidelijker te laten zien.
Trouwens nog even een vraagje over ppp,
Ik maak 9 van de 10 keer al mijn variablen private, en schrijf er dan een get en set voor.
Vanuit daar maak k dan eigenlijk geen onderscheid tussen public en protected, maar is dat een heel groot probleem, het maakt mij namelijk niet extreem veel uit of hij buiten de class wel of niet beschikbaar is, zolang de privates dat maar niet zijn.
als ik bijvoorbeeld een user heb, dan ziet die class er ongeveer zo uit:
Maar als k dan iets protected zou willen maken, dan moet k dus gewoon de functies protected maken?
Of heeft iemand betere ideeën.
Ik maak 9 van de 10 keer al mijn variablen private, en schrijf er dan een get en set voor.
Vanuit daar maak k dan eigenlijk geen onderscheid tussen public en protected, maar is dat een heel groot probleem, het maakt mij namelijk niet extreem veel uit of hij buiten de class wel of niet beschikbaar is, zolang de privates dat maar niet zijn.
als ik bijvoorbeeld een user heb, dan ziet die class er ongeveer zo uit:
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
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
<?php
class User
{
private $id;
private $username;
private $email;
private $password;
public function getId()
{
return $this->id;
}
public function setId($id)
{
//exception gooien, want dat mag helemaal niet.
}
public function getUsername()
{
return $this->username;
}
public function setUsername($username)
{
if (//controle is goed, let op niet in gebruik en valid en alles)
$this->username = $username;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
if (//controle is goed, let op niet in gebruik en valid en alles)
$this->email = $email;
}
public function getPassword()
{
//Die heb je toch niet nodig, dus die doet niks
}
public function setPassword($password)
{
$this->password = $password;
}
?>
class User
{
private $id;
private $username;
private $email;
private $password;
public function getId()
{
return $this->id;
}
public function setId($id)
{
//exception gooien, want dat mag helemaal niet.
}
public function getUsername()
{
return $this->username;
}
public function setUsername($username)
{
if (//controle is goed, let op niet in gebruik en valid en alles)
$this->username = $username;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
if (//controle is goed, let op niet in gebruik en valid en alles)
$this->email = $email;
}
public function getPassword()
{
//Die heb je toch niet nodig, dus die doet niks
}
public function setPassword($password)
{
$this->password = $password;
}
?>
Maar als k dan iets protected zou willen maken, dan moet k dus gewoon de functies protected maken?
Of heeft iemand betere ideeën.
In plaats van setters en getters te schrijven voor elke membervariabele in een class gebruik ik vaak de magic methods __set en __get:
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
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
<?php
ini_set ('display_errors', 1);
error_reporting (E_ALL | E_STRICT);
class Foo {
private $vars = array ();
public function __set ($key, $value) {
$this->vars[$key] = $value;
}
public function __get ($key) {
if (isset ($this->vars[$key])) {
return $this->vars[$key];
}
else {
throw new Exception ('De membervariabele <strong>' . $key . '</strong> bestaat niet');
}
}
}
try {
$foo = new Foo ();
$foo->tekst = 'Hallo wereld';
$foo->getallen = range (0, 10);
echo '<pre>' . print_r ($foo, true) . '</pre>';
foreach ($foo->getallen as $getal) {
echo '<pre>' . print_r ($getal, true) . '</pre>';
}
echo '<pre>' . print_r ($foo->niet_bestaande_var, true) . '</pre>';
}
catch (Exception $e) {
echo '<p>' . $e->getMessage () . '</p>';
}
?>
ini_set ('display_errors', 1);
error_reporting (E_ALL | E_STRICT);
class Foo {
private $vars = array ();
public function __set ($key, $value) {
$this->vars[$key] = $value;
}
public function __get ($key) {
if (isset ($this->vars[$key])) {
return $this->vars[$key];
}
else {
throw new Exception ('De membervariabele <strong>' . $key . '</strong> bestaat niet');
}
}
}
try {
$foo = new Foo ();
$foo->tekst = 'Hallo wereld';
$foo->getallen = range (0, 10);
echo '<pre>' . print_r ($foo, true) . '</pre>';
foreach ($foo->getallen as $getal) {
echo '<pre>' . print_r ($getal, true) . '</pre>';
}
echo '<pre>' . print_r ($foo->niet_bestaande_var, true) . '</pre>';
}
catch (Exception $e) {
echo '<p>' . $e->getMessage () . '</p>';
}
?>
Het grote nadeel van die magic methods is dat je ze niet specifiek voor een variable kan schrijven.
Zo kan je op die manier niet controleren of het e-mail adres wel echt een e-mail adres is.
In C# en een paar andere talen kan dit nog veel mooier, daar kan je voor iedere variable een aparte get en set schrijven.
En ik vind het bijvoorbeeld best belangrijk dat een password wel te setten is,, en niet te getten.
Zo kan je op die manier niet controleren of het e-mail adres wel echt een e-mail adres is.
In C# en een paar andere talen kan dit nog veel mooier, daar kan je voor iedere variable een aparte get en set schrijven.
En ik vind het bijvoorbeeld best belangrijk dat een password wel te setten is,, en niet te getten.
@nico
Maar je gebruikt die "magic methods" toch algemeen, en voor de rest gebruik je een controle methode erbij?
Maar je gebruikt die "magic methods" toch algemeen, en voor de rest gebruik je een controle methode erbij?
Het kan wel, soort van... maar het heeft niet echt meerwaarde boven normale getters en setters. Ik vind het zelf meer verwarrend.
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
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
<?php
abstract class MagicObject
{
public function __set($key, $value)
{
if(!method_exists($this, 'set_' . $key))
throw new Exception("Property $key is read-only");
call_user_func(array($this, 'set_' . $key), $value);
}
public function __get($key)
{
if(!method_exists($this, 'get_' . $key))
throw new Exception("Instance of " . get_class($this) . " does not have a property $key");
return call_user_func(array($this, 'get_' . $key));
}
}
class User extends MagicObject
{
public $vrij_toegankelijk;
protected $username;
protected $hash;
protected function get_username()
{
return $this->username;
}
protected function set_username($username)
{
if(!preg_match('{^[a-z0-9]{3,10}$}i', $username))
throw new InvalidArgumentException("Username should be between 3 and 10 chars");
$this->username = $username;
}
protected function set_password($password)
{
$this->hash = md5($password);
}
}
$x = new User();
$x->vrij_toegankelijk = 24;
assert('$x->vrij_toegankelijk === 24');
$x->username = 'Taart';
assert('$x->username === "Taart"');
try {
$x->username = 'pinda-kaas';
assert(false);
} catch(Exception $e) {
assert('$e instanceof InvalidArgumentException');
}
$x->password = 'Hundertwasser';
try {
echo $x->password;
assert(false);
} catch(Exception $e) {
assert('$e->getMessage() == "Instance of User does not have a property password"');
}
?>
abstract class MagicObject
{
public function __set($key, $value)
{
if(!method_exists($this, 'set_' . $key))
throw new Exception("Property $key is read-only");
call_user_func(array($this, 'set_' . $key), $value);
}
public function __get($key)
{
if(!method_exists($this, 'get_' . $key))
throw new Exception("Instance of " . get_class($this) . " does not have a property $key");
return call_user_func(array($this, 'get_' . $key));
}
}
class User extends MagicObject
{
public $vrij_toegankelijk;
protected $username;
protected $hash;
protected function get_username()
{
return $this->username;
}
protected function set_username($username)
{
if(!preg_match('{^[a-z0-9]{3,10}$}i', $username))
throw new InvalidArgumentException("Username should be between 3 and 10 chars");
$this->username = $username;
}
protected function set_password($password)
{
$this->hash = md5($password);
}
}
$x = new User();
$x->vrij_toegankelijk = 24;
assert('$x->vrij_toegankelijk === 24');
$x->username = 'Taart';
assert('$x->username === "Taart"');
try {
$x->username = 'pinda-kaas';
assert(false);
} catch(Exception $e) {
assert('$e instanceof InvalidArgumentException');
}
$x->password = 'Hundertwasser';
try {
echo $x->password;
assert(false);
} catch(Exception $e) {
assert('$e->getMessage() == "Instance of User does not have a property password"');
}
?>
Die __set en __get gebruik ik meestal in combinatie met het Registry pattern, als alternatief voor het gebruik van globals. Voor variabelen waar een check op zit gebruik ik of een aparte get/set method, of ik doe het via een class String waar de validatie in zit.
Gewijzigd op 01/01/1970 01:00:00 door Jan Koehoorn
Wat mij mooi zou lijken voor PHP, wat ook al beschikbaar is voor C#, is dit.
Maar ik ben bang dat dat hem niet gaat worden met php
Code (php)
Maar ik ben bang dat dat hem niet gaat worden met php
hierbij mijn inzendig:
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
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
<?php
class Dier
{
private $_soort;
private $_naam;
public function Dier($naam,$soort)
{
$this->naam = $naam;
$this->soort = $soort;
}
public function getNaam()
{
return $this->naam;
}
public function getSoort()
{
return $this->soort;
}
}
class Koe extends Dier
{
public function __construct($naam)
{
Dier::__construct($naam,'Koe');
}
public function maakGeluid()
{
$this->geluid = 'Boeeeeeeeee';
return $this-geluid;
}
}
class Schaap extends Dier
{
public function __construct($naam)
{
Dier::__construct($naam,'Schaap');
}
public function maakGeluid()
{
$this->geluid = 'Meeeeeeee';
return $this->geluid;
}
}
?>
class Dier
{
private $_soort;
private $_naam;
public function Dier($naam,$soort)
{
$this->naam = $naam;
$this->soort = $soort;
}
public function getNaam()
{
return $this->naam;
}
public function getSoort()
{
return $this->soort;
}
}
class Koe extends Dier
{
public function __construct($naam)
{
Dier::__construct($naam,'Koe');
}
public function maakGeluid()
{
$this->geluid = 'Boeeeeeeeee';
return $this-geluid;
}
}
class Schaap extends Dier
{
public function __construct($naam)
{
Dier::__construct($naam,'Schaap');
}
public function maakGeluid()
{
$this->geluid = 'Meeeeeeee';
return $this->geluid;
}
}
?>
Gewijzigd op 01/01/1970 01:00:00 door Roeltje M


