Multiple class extends
Code (php)
Ik begrijp dat ik de classes achter elkaar wil hangen, maar er zijn situates waarbij ik geen classes wil laden die ik niet nodig heb.
Wie helpt?
Dit wordt voor php te complex.
Ook zijn er dan veel dingen waar je rekening mee moet houden.
Bijvoorbeeld:
Welke constructor moet er gekozen worden? Die van "basic" of die van "input"?
Uiteraard ook die van "main", maar die roept dan weer de contructor van zijn parent aan.
Hiernaast wordt dan ook de engine van php te complex en beduidend langzamer.
Composition is dat je simpelweg een instantie van de iets-anders klasse binnen je iets klasse gebruikt. Simpel voorbeeld. Een klasse 'spaak' extend de klasse 'wiel' niet. Een spaak is immers geen wiel, dus heeft ook niets aan de eigenschappen en methoden van een wiel. Maar de spaak heeft misschien wel een referentie naar de instantie van 'wiel' waar hij deel van uitmaakt, en andersom ook. 'wiel' heeft een array vol met instanties van 'spaken'. Zo zijn ze toch met elkaar verbonden en kan je ze prima gebruiken, zonder dat ze elkaar extenden.
Code (php)
Zoals je ziet kan je enkel maar correct een klasse extenden als die ook hetzelfde is in grote lijnen.
hoewel de post misschien niet meer actueel is wil ik toch reageren.
Voor een project had ik namelijk een aantal interfaces; oa. Registry en Singleton.
Omdat ik een uniforme implementatie van Registry en Singleton wilde handhaven implementeerde ik deze patronen in abstracte classes.
Het was de bedoeling om een Settings en Session class te implementeren als een Registry (extends). Session moest ook een Singleton zijn dus zou logischerwijs Singleton extenden.
Mijn 'probleem' is dus dat ik ook SingletonRegistry moet implementeren, die ofwel extends Registry OF extends Singleton, maar die altijd redundante code zou bevatten (resp. Singleton OF Registry).
Sidenote: Ik had ook al gedacht aan Session extends Registry implements Singleton maar dat komt op hetzelfde neer. In mijn ogen is een class SingletonRegistry een elegantere oplossing.
Is er geen elegante manier om dit op te lossen? Ik *haat* redundant code... :D
Een oplossing is composition. Middels de interface dwing je de methods die nodig zijn om bijvoorbeeld de Registery-implementatie mogelijk te maken (getValueForKey, setValueForKey etc.) en je dwingt een method getRegistery() af bijvoorbeeld. In je constructor maak je dan een instantie van een algemene registery-klasse, waarbij de constructor 1 argument slikt, een 'delegate' die de interface implementeert. Zo kan de instantie van de algemene registery-klasse zijn werk doen, en kan je hem benaderen middels [ImplementerendeKlasse]::getRegistery()
Resultaat is dat je het gedrag hebt afgedwongen middels een interface, dat je alle 'algemene' code in 1 klasse kan houden en dat je meerdere interfaces tegelijkertijd kan implementeren (zoals het hoort :))
Volgens mij maakt SPL er bij zijn ArrayIterator ook gebruik van zo'n soort manier.
Je vorige post over compo sloeg ik al meteen over omdat ik het nut er in mijn geval niet van inzag, Session is een Registry én een Singleton dusja...
Jouw oplossing lost het probleem van redundante code op, wat toch het doel was.
Hieronder voorbeeldcode die bij de oplossing hoort, voor het geval iemand anders ooit hetzelfde probleem tegenkomt.
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Session extends Singleton implements IRegistry {
private $registry = null;
public function __construct() {
// Importereer session en verwijder
$this->registry = new Registry();
// Sla session info op in registry
}
public function register($strKey) {
if ($this->registry instanceof Registry) {
$this->registry->register($strKey);
} else {
// Throw exception
}
}
.....
}
?>
class Session extends Singleton implements IRegistry {
private $registry = null;
public function __construct() {
// Importereer session en verwijder
$this->registry = new Registry();
// Sla session info op in registry
}
public function register($strKey) {
if ($this->registry instanceof Registry) {
$this->registry->register($strKey);
} else {
// Throw exception
}
}
.....
}
?>
Maar wat als Registry aangepast wordt? Of eender welke andere uitbreiding van Singleton (staat bijna nooit op zichzelf)?
Dan zou ik dus ook de Session (of andere) implementatie moeten updaten. Nu wordt dit uiteraard wel afgedwongen door de interface IRegistry dus op zich geen probleem.
Maar 'voor de sport' ga ik een stap verder:
Een algemene implementatie, die er wrs een beetje over gaat. Gotta love overloading :D.
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
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
<?php
class CompositeSingleton extends Singleton {
private $instance = null;
public function __construct($className) {
$this->$instance = new $className();
}
public function __call($function, $args) {
if (method_exists($this->instance, $function)) {
return call_user_func_array($this->instance->$function, $args);
} else {
// throw Exception
}
}
}
class Session extends CompositeSingleton {
public function __construct() {
// Importeer sessie
parent::__construct("Registry");
}
}
?>
class CompositeSingleton extends Singleton {
private $instance = null;
public function __construct($className) {
$this->$instance = new $className();
}
public function __call($function, $args) {
if (method_exists($this->instance, $function)) {
return call_user_func_array($this->instance->$function, $args);
} else {
// throw Exception
}
}
}
class Session extends CompositeSingleton {
public function __construct() {
// Importeer sessie
parent::__construct("Registry");
}
}
?>
Merk op dat Session niet langer de interface IRegistry implementeert... Er is dus geen enkele referentie meer naar de IRegistry interface of de Registry baseclass.
Thx voor de tip Jelmer!!
/edits: Formatting + foutjes + wat meer tekst :-*
Gewijzigd op 01/01/1970 01:00:00 door bluecherry