Ola,

Ik heb een vraagje en wellicht kan iemand mij een duwtje in de goede richting geven.

Hoe moet je precies een interface gebruiken?

Maak je een interface op method niveau, of op class niveau?

Is het bijvoorbeeld de bedoeling dat je een datacollectionInterface maakt, met als methods get() en set(). Of is het de bedoeling dat je een getInterface en een setInterface, en dan eventueel een getSetInterface die die 2 andere interfaces extend?

Ik wil vooral de achterliggende gedachte van een interface proberen te begrijpen. Ik hoop dat iemand dat op een simpele manier kan uitleggen, want ik ben een beetje bang dat ik het anders verkeerd aanpak, om er vervolgens over een paar weken achter te komen dat ik alles opnieuw kan doen.

Kan iemand me een beetje wegwijs maken? Hoeft echt geen lang verhaal te zijn, maar met name hoe ik mijn interfaces het beste kan opbouwen. Even een zetje in de goede richting zeg maar. Alvast bedankt.
Tutorials zijn er genoeg. Wat ik vooral wil weten is op welke manier je een interface gebruikt.

Wat me opvalt is dat er mensen zijn die een interface gebruiken om één bepaalde method af te dwingen, en dat er mensen zijn die een interface gebruiken om de invulling van een class af te dwingen.

Een voorbeeld van het afdwingen van één method: printableInterface (de class moet een print method hebben)

Een voorbeeld van het afdwingen van een class: databaseInterface (de class moet een setQuery en execcute method hebben)

Eigenlijk heb ik 2 vragen:

1) gebruik je normaal gesproken beide methodes?

2) wanneer gebruik je een interface? Hoe weet je vantevoren of je een interface nodig hebt?
Je gebruikt een interface wanneer je wilt dat een klasse een methode verplicht implementeert. Je hoeft in die methodes verder niet alles verplicht vullen met logica maar zolang je die methodes maar erin hebt zitten. zo kan elke klasse die er gebruik van maakt de methode op eigen manier invullen. even een voorbeeldje


<?php
interface QuackBehavior {

public function quack();

}

class RubberDuck implements QuackBehavior {

public function quack()
{
return 'silence';
}

}

class RiverDuck implements QuackBehavior {

public function quack()
{
return 'quaaaackk!!';
}

}

?>

Op deze manier verplicht je dat een klasse bepaalde methodes moet implementeren maar je bent vrij om zelf te bepalen hoe je deze invult.
Je gebruikt een interface om bepaalde functionaliteit af te dwingen. Of je voor die functionaliteit maar een methode of meerdere, of helemaal geen (marker pattern) nodig hebt hangt van de situatie af. (Ja, dit komt bijna elke keer terug)

interface Countable dwingt alleen de methode count() af om te kunnen gebruiken in count().
interface Serializable dwingt methoden serialize() en unserialize() af om het te kunnen gebruiken in de serialize() en unserialize() functies.
interface Iterator dwringt methoden current(), next(), key(), rewind() en valid() af het te gebruiken in een foreach.

Oké. Stel nu ik heb een algemene data class waarin verschillende soorten data kunnen worden opgeslagen. Zo'n class heeft een get(), has() en set() method. Wat zijn dan redenen om hier een interface voor te maken, en op welke wijze kun je dat het beste doen?

Moet ik bijv. een losse getInterface, hasInterface en setInterface maken, en dan vervolgens een dataInterface die deze 3 interfaces extend?

Daarnaast vraag ik me ook af hoe je een interface moet noemen. Want hierboven zie ik "...able" interfaces. CountABLE, SerializABLE. Maar het kan ook een zelfstandig naamwoord zijn: IteratorInterface, DatabaseInterface. Zijn daar bepaalde redenen voor?
*Interface voor de namen altijd. Dat is de standaard.

En je moet ook niet voor alles een interface maken, dat is niet altijd nodig. Als je bijvoorbeeld verschillende type's classen hebt, bv.:

<?php

interface CarInterface {
	public function getNaam();
	public function getWielen();
}

class Volvo implements CarInterface {
	public function getNaam() { return "Volvo"; }
	public function getWielen() { return 4; }
}

class Citroen implements CarInterface {
	public function getNaam() { return "Citroen"; }
	public function getWielen() { return 4; }
}

$autos = [new Volvo(), new Citroen()];

foreach($autos as $auto) {
   if ($auto instanceof CarInterface) {
       echo $autos->getNaam();
   }
}
?>


Waarom hier nu een interface? Je hebt een foreach loop. Maar die array kan alles bevatten, maar omdat we verwachten we dat getNaam() in de interface verplicht word kunnen we die veilig gebruiken.

[hr]

Wat heel belangrijk is, en vooral voor jou in het bijzondere Ozzie, is dat je eerst zelf wat dingen uitprobeert. Dan worden de use-cases van een interface vanzelf duidelijk.
"*Interface voor de namen altijd. Dat is de standaard."
Dat hangt af van wie je het vraagt, over welke taal je het hebt etc.


<?php

function consume(Consumable $substance) { ... } // function consume consumes a Consumable substance
function repair(Repairable $object) { ... } // function reparair repairs a Repairable substance

// versus

function consume(ConsumeInterface $substance) { ... } // function consume consumes a ConsumeInterface instance
function repair(RepairInterface $object) { ... } // function repair repairs a RepairInterface instance

// conclusie: *able vormt een beter over de tong rollende zin

?>

"Moet ik bijv. een losse getInterface, hasInterface en setInterface maken, en dan vervolgens een dataInterface die deze 3 interfaces extend?"
Als jij denkt dat je ze soms afzondelijk wilt implementeren...

<?php

// dit is bijvoorbeeld GEEN goed idee

class Meow {

private $object;

public function __construct(GetInteface $object) {
$this->object = $object;
}

public function doGet() {
// prima zolang Meow::setObject() niet is aangeroepen...
return $this->object->get();
}

public function doHas($mixed) {
// dit is onzin aangezien GetInterface alleen get() forceert
return $this->object->has($mixed);
}

public function doSet($mixed) {
// alleen correct als eerst Meow::setObject() is aangeroepen
return $this->object->set($mixed);
}

public function setObject(SetInterface $object) {
// Meow::$object was eerst een GetInterface instantie, nu wordt het een SetInterface instantie...
// WTF!?!
$this->object = $object;
}
}

?>

Groepeer wat logisch is. Als het later blijkt dat opsplitsen logisch is kan het dan altijd nog. Ook is het niet veel werk omdat je alleen de interface aan hoeft te passen.
Als je het eerst opsplitst en later bedenkt dat het toch niet zo handig was is het meer moeite.
>> *Interface voor de namen altijd. Dat is de standaard.

Wat bedoel je Raoul?

@Dos: ik snap je voorbeeld niet helemaal :-s

Waarom dwing je bij setObject een SetInterface af?

>> Groepeer wat logisch is. Als het later blijkt dat opsplitsen logisch is kan het dan altijd nog. Ook is het niet veel werk omdat je alleen de interface aan hoeft te passen.

Zal ik onthouden. Goede tip.
*Interface
Wat betekent bv. CarInterface, niet *able.

En dos, we hebben het hier uiteraard over PHP en niet over een andere taal.
Ah oké, dat bedoelde je... ik dacht even dat je bedoelde interface vóór de namen, dus InterfaceCar. Maar nu begrijp ik je :)

Toevoeging op 07/03/2014 14:31:33:

Overigens... als in m'n interface een set method afdwing, kan ik dan in de class die die interface implement geen hints gebruiken? Dat lijkt namelijk niet te werken:

<?php

interface FooInterface {

public function foo($bar);

}

class Foo implements FooInterface {

public function foo(Bar $bar) {

}

}

?>
Dit gaat fout, omdat ik in de Foo class in de foo() method een instance van Bar afdwing. Maar dat gaat dus niet. Dat is niet handig... want stel we hebben bijv. een set() method, dan wil ik soms dat de value een array is, en soms dat het een object is. Hoe doe ik zoiets dan?

Reageren