Een workaround niet, een oplossing wel. Wat je zal moeten doen is je classe structuur anders opbouwen en dan de functionaliteit onderbrengen in aparte classes. Die classes (en functionaliteit) kan je dan door je voertuig classes laten gebruiken. Zo kan een auto gebruik maken van de 'rij' functionalieit, maar ook het amfibie. De 'vaar' functionaliteit kan door een boot worden gebruikt en ook weer door een amfibie.
Dit wordt ook wel het strategy design pattern genoemd: http://en.wikipedia.org/wiki/Strategy_pattern
Wat staat er precies in de klassen Autovoertuig en Watervoertuig? Naar mijn mening werkt een amfibievoertuig anders dan een auto of watervoertuig en hoort het daarom niet over te erven van deze klassen. Ik zou dan iets als dit doen:
interface VoertuigInterface;
interface DrijfbaarVoertuigInterface extends VoertuigInterface;
interface RijdbaarVoertuigInterface extends VoertuigInterface;
abstract class StuurbaarVoertuig implements VoertuigInterface;
class AutoVoertuig extends StuurbaarVoertuig implemets RijdbaarVoertuigInterface;
class WaterVoertuig extends StuurbaarVoertuig implements DrijfbaarVoertuigInterface;
class AmfibieVoertuig extends StuurbaarVoertuig implements RijdbaarVoertuigInterface, DrijfbaarVoertuigInterface;
[hr]
Het strategy pattern had ik nog niet aan gedacht, is ook een mooie oplossing:
interface WaterGedrag;
interface VasteGrondGedrag;
interface VoertuigInterface;
class DrijfGedrag implements WaterGedrag;
class ZinkGedrag implements WaterGedrag;
...
class RijGedrag implements VasteGrondGedrag;
class SchuifGedrag implements VasteGrondGedrag;
...
class Voertuig implements VoertuigInterface;
En dan in gebruik:
<?php
$auto = new Voertuig();
$auto->setVasteGrondGedrag(new RijGedrag());
$auto->setWaterGedrag(new ZinkGedrag());
$boot = new Voertuig();
$boot->setVasteGrondGedrag(new SchuifGedrag());
$boot->setWaterGedrag(new DrijfGedrag());
$amfibie = new Voertuig();
$amfibie->setVasteGrondGedrag(new RijGedrag());
$amfibie->setWaterGedrag(new DrijfGedrag());
?>
Bedankt voor de reacties. Ik bedoel eigenlijk zoiets als onderstaande. Volgens mij is zoiets wel mogelijk in Delphi en ik zoek een workaround in PHP.
class Autovoertuig
{
function GaVooruit()
{
}
}
class Watervoertuig
{
function GaVooruit()
{
}
}
class Amfibievoertuig extends Autovoertuig, Watervoertuig
{
public IsModusAutoOfBoot;
function GaVooruit()
{
if (IsModusAutoOfBoot=='auto')
{
Autovoertuig.GaVooruit;
}
elseif (IsModusAutoOfBoot=='boot')
{
Watervoertuig.GaVooruit;
}
}
}
Vanaf PHP 5.4.0 kun je multiple inheritance nabootsen met multiple traits.
<?php
trait Rijden
{
// ...
}
trait Varen
{
// ...
}
class Amfibievoertuig
{
use Rijden, Varen;
// ...
}
?>
Als je echter, zoals in jouw opzet, één gedeelde methode GaVooruit() hebt die bij 'boot' anders reageert dan bij 'auto', dan heb je meer twee klassen die afstammen van één en dezelfde ouderklasse. Dan krijg je eerder dit:
<?php
class Amfibievoertuig
{
// Kan varen én rijden.
}
class Auto extends Amfibievoertuig
{
// Kan alleen rijden.
}
class Boot extends Amfibievoertuig
{
// Kan alleen varen.
}
?>
Je kunt dus omgekeerd redeneren: een auto is een amfibievoertuig dat niet kan varen en een boot is een amfibievoertuig dat niet kan rijden.
Om eerlijk te zijn lijkt dat laatste me een zeer foute manier. Want je hebt ook nog treinen, die rijden op een spoor. Maar sommige vrachtwagens die aan het spoor werken hebben ook de mogelijkheid om op het spoor te rijden. Dus nu moet je dan al een nog grotere basisklas hebben die ook op het spoor kan rijden zodat je die vrachtwagens die op het spoor kunnen rijden hiermee ook kunt bouwen.
Zo krijg je het vliegende rubber eendjes verhaal, voor degene die het boek kennen. Niet doen op die manier.
[size=xsmall]Toevoeging op 11/06/2013 17:12:15:[/size]
Hank Noseman op 11/06/2013 16:29:34
Bedankt voor de reacties. Ik bedoel eigenlijk zoiets als onderstaande. Volgens mij is zoiets wel mogelijk in Delphi en ik zoek een workaround in PHP.
Erwin, ik ging ervan uit dat het niet echt over amfibievoertuigen of badeenden gaat :)
Het logicaprobleem bij multiple inheritance is dat je een vader en een moeder hebt die beide anders lopen: ze hebben beide een methode GaVooruit(). Dat betekent dat je een kind altijd voor een keuze stelt: loop je zoals vader, zoals moeder of zoals een mengelmoes?
Met multiple traits LopenAlsEenMan en LopenAlsEenVrouw los je dat deels op.
Het alternatief is niet elegant, dat ben ik met je eens, maar dat is inherent aan het ontbreken van multiple inheritance in PHP: je bouwt beide varianten van de methode in en laat een afgeleide klasse de methode kiezen.
Zo ongebruikelijk is dat overigens natuurlijk niet: in veel constructors kun je immers ook kiezen welke "smaak" je van een klasse wilt hebben.
En daarom is het strategy patern juist zo mooi. Daarmee bereik je precies hetzelfde, het is veel flexibeler en je voorkomt dat functionaliteit op een rare manier achter blijft daar waar je het niet wil hebben.
En daarom is het strategy patern juist zo mooi. Daarmee bereik je precies hetzelfde, het is veel flexibeler en je voorkomt dat functionaliteit op een rare manier achter blijft daar waar je het niet wil hebben.
Goed punt. Wat vind je dan van gedeelde functionaliteit in gemeenschappelijke traits die je expliciet moet aanroepen met use?
Met traits heb ik nog te weinig ervaring om daar een mening over te geven. Ik ga daar zo wel even naar kijken, maar meer uitleg van jouw kant (hoe traits hierbij een rol kunnen spelen) waardeer ik wel.
Ik denk dat de zoektocht naar een passende naam al veelzeggend is. Een trait is een kenmerk, maar hadden we daarvoor in ruil al niet de property of eigenschap en de function voor bepaalde functionaliteit?
Eerlijk gezegd heb ik zo mijn bedenkingen. Traits kunnen dingen doen die ik liever niet terugzie in een grootschalig project.
Neem bijvoorbeeld deze uitbreiding op een vorig voorbeeld:
<?php
trait Rijden
{
// ...
}
trait Varen
{
// ...
}
trait Vliegen
{
// ...
}
class Amfibievoertuig
{
use Rijden, Varen, Vliegen;
// ...
}
?>
Met één simpele uitbreiding van use Rijden, Varen, Vliegen kan het amfibievoertuig plotseling ook vliegen. En die trait Vliegen geeft de klasse meteen alle methoden van de trait.
Is dat nu handig of gevaarlijk? Ik weet het niet, de waarheid zal ongetwijfeld ergens in het midden liggen.