[oop] lege class
Pagina: « vorige 1 2 3 4 volgende »
- class PathsCollection extends DataCollection
- abstract class DataCollection implements ArrayAccess, Countable, Serializable
Ik heb nu voor de DataCollection wel een interface gemaakt, die Countable en IteratorAggregate extendt.
Waar is die Serializable goed voor?
Serializable interface van pas. Dat is natuurlijk ook een keuze, zoals alles, maar ik noemde het voorbeeld omdat deze ontwerpbeslissing eerder thuishoort op het niveau DataCollection dan op het niveau PathsCollection extends DataCollection.
Als je objecten wilt cachen, komt de Hoe kijk jij tegen het typehinten aan wat betreft inhoud. Is typehinten ook bedoeld om te voorkomen dat een obejct met "verkeerde" inhoud wordt gebruikt? (zie dit topic: http://www.phphulp.nl/php/forum/topic/oop-typehinten/94179/last/)
Wat is "verkeerde inhoud"? Als je bijvoorbeeld een ongewenst datatype of een ongeldige datastructuur bedoelt, dan is het antwoord volmondig: ja, je kunt nooit te veel typehinten, wel te weinig.
Je hebt een object Foo en dat object heeft een object met Paden nodig. We hadden net vastgesteld dat PathsCollection en DataCollection is, en DataCollection implement een DataCollectionInterface. PathsCollection implement (via DataCollection) dus ook een DataCollectionInterface.
Goed, we hebben in class Foo dus een PathsCollection nodig. Die kan ik als volgt typehinten:
Code (php)
Wat we nu dus in feite zeggen, is dat we een object willen wat voldoet aan de DataCollectionInterface. Echter, in plaats van een PathsCollection, zou ik dus ook een ConfigCollection, RoutesCollection of FooBarCollection kunnen meegeven. Is dat gebruikelijk? Of a) moet niet naar een interface maar naar een class (PathsCollection) typehinten, of b) moet ik wellicht een nieuwe PathsCollectionInterface maken, en daar naar typehinten?
interface PathsCollectionInterface extends DataCollectionInterface {}
class PathsCollection extends DataCollection implements PathsCollectionInterface { ... }
Gewijzigd op 10/03/2014 17:23:08 door Dos Moonen
Maar is dit ook de bedoeling van het gebruik van interfaces? Moet een interface daar tegen "beschermen"? Dus in dit specifieke voorbeeld, moet een interface er voor waken dat ik alleen paden kan ingeven (en niet bijv. routes of configuratiesettings). Is dat waar een interface voor dient?
Als je naast een PathsCollection nog een ConfigCollection en een RoutesCollection hebt, dan zou ik $paths wel concreet typehinten met PathsCollection $paths, niet met het ruimere DataCollectionInterface $paths. De klasse implementeert de interface (direct): je kunt dat niet meer elegant ombuigen als je dat (indirect) met de typehint op de interface doet in Foo.
En de andere oplossing, om een aparte PathsCollectionInterface te maken (zie hierboven het voorbeeld van Dos)?
class PathsCollection implements PathsCollectionInterface
ooit vervangt door bijvoorbeeld
class PathsCollection implements CloudDataMapperInterface
dan heb je elders nog steeds op verschillende plaatsen de (verouderde) typehint PathsCollectionInterface $paths. Het implementeren van de interface zou ik daarom, zoals gezegd, in dit geval liever direct doen via de definitie van de klasse die de interface daadwerkelijk implementeert, niet indirect via op verschillende plaatsen rondzwervende typehints.
Gewijzigd op 10/03/2014 17:58:00 door Dos Moonen
Dan heb ik liever één update van één klasse dan tientallen updates van evenveel typehints.
De code hoeft ook niet per se te breken, want je zou kunnen opschalen:
class PathsCollection implements PathsCollectionInterface, CloudDataMapperInterface
Dan ondersteunt de klasse de oude en de nieuwe interface, maar werken de typehints nog steeds met de oude interface. En ja, dat kan zowel een voordeel als een nadeel zijn.
Als we weer even terugkomen op een PathsCollection en een ConfigCollection. Beide ondersteunen dezelfde interface DataCollectionInterface. Als ik nu ergens in class Foo een PathsCollection nodig heb, volstaat het dan om te typehinten op DataCollection (hiermee dwingen we de benodigde methodes af) of is het beter om (ook) te typehinten op functionaliteit (ik wil enkel een PathsCollection en dus geen ConfigCollection)?
>> Dat is ook een mooie oplossing, maar heeft één nadeel. ... dan heb je elders nog steeds op verschillende plaatsen de (verouderde) typehint PathsCollectionInterface $paths.
Ward, ik snap precies wat je bedoelt... maar is dit niet altijd het geval?
Misschien begrijp ik je verkeerd, maar als ik het goed begrijp dan hebben we een interface X, en meerdere classes ondersteunen die interface. Dat is handig want dan weten we dat al die classes dezelfde methodes hebben. Als ik van de een op de andere dag besluit dat class Foo een bepaalde interface niet meer ondersteunt, dan lijkt het me logisch dat ik de boel breek. Maar dat is toch in alle gevallen zo?
Dat is eigenlijk hetzelfde. Via constanten beschrijf je wat elke implementatie van de interface "is" en via methoden wat elke implementatie kan "worden" of kan "doen". (Waarmee we voor de liefhebbers en passant mooi even het verschil hebben afgedekt tussen een functie en een procedure.) In dat opzicht lijkt het vrij letterlijk het spelletje Hints: je kunt via hints een ding omschrijven, zolang je het ding zelf maar niet met naam noemt.
>> Misschien begrijp ik je verkeerd, maar als ik het goed begrijp dan hebben we een interface X, en meerdere classes ondersteunen die interface. Dat is handig want dan weten we dat al die classes dezelfde methodes hebben. Als ik van de een op de andere dag besluit dat class Foo een bepaalde interface niet meer ondersteunt, dan lijkt het me logisch dat ik de boel breek. Maar dat is toch in alle gevallen zo?
Dat is ook logisch, maar dan wil ik liever het breekpunt zien in de klasse die de interface implementeert, niet in alle typehints van andere klassen die die ene klasse gebruiken.
Mijn punt is vooral dat als je al een class Foo implements FooInterface hebt, een typehint zoals __construct(FooInterface $foo) of methode(FooInterface $foo) eerder in de weg zit dan iets toevoegt. De implementatie van de interface wordt al direct afgedwongen door de klasse. Het is dubbelop om dat nog eens indirect over te doen met een typehint in alle andere klassen die deze ene klasse gebruiken. En één klasse kun je makkelijker verbouwen dan alle typehints van de interface.
Wat bedoel je hier met "constanten"? Bedoel je daarmee de naam van de interface?
>> De implementatie van de interface wordt al direct afgedwongen door de klasse.
Ik snap wat je bedoelt. Maar omgekeerd betekent het ook weer dat ik dus overal waar ik naar de class typehint, alleen die ene specifieke class kan gebruiken, en dus geen varianten van de PathsCollection class. Een FooPathsCollection zou dus niet werken, terwijl die bijv. wel de PathsCollectionInterface ondersteunt. Ik meen ooit gehoord te hebben dat je om die reden zoveel mogelijk naar interfaces moet programmeren, maar ik kan me vergissen.
Nee, in een interface kun je niet alleen methoden maar ook constanten vastleggen. Daarmee beschrijf je dus niet alleen wat alle objecten met die interface kunnen "worden" (de methoden), maar ook wat ze in eerste aanleg bij hun geboorte al "zijn" (de constanten).
>> Ik snap wat je bedoelt. Maar omgekeerd betekent het ook weer dat ik dus overal waar ik naar de class typehint, alleen die ene specifieke class kan gebruiken, en dus geen varianten van de PathsCollection class.
Ja, maar ik neem aan dat als je een __construct($paths) voor paden nodig hebt, je dat redelijk dicht op de __construct(PathsCollection $paths) class-hint wilt programmeren, niet op de veel ruimere __construct(DataCollection $paths) interface-hint. Doe je dat namelijk niet, dan gooi je alles dat je speciaal voor paden aan PathsCollection hebt toegevoegd overboord.
Bovendien krijg je dan voor paden geen echt PathsCollection-object, maar meer een generiek DataCollection-object en zou je dus, per ongeluk, ook een ConfigCollection-object kunnen gebruiken waar je eigenlijk een PathsCollection-object nodig hebt.
Kun je hiervan een voorbeeldje geven?
>> Ja, maar... nodig hebt.
Helemaal mee eens. Maar waarom zou je niet een PathsCollectionInterface maken?
Wat betreft mijn andere vraag...
Quote:
Helemaal mee eens. Maar waarom zou je niet een PathsCollectionInterface maken?
Kun je dit nog toelichten? Ik weet ook niet of het een goed idee is om een PathsCollectionInterface te maken. Want ben je dan straks niet bezig om voor iedere class een interface te maken? Dat lijkt me ook weer niet de bedoeling. Maar waar leg je dan die grens? Anders gezegd: hoe bepaal je of je moet typehinten naar een class of naar een interface? Kunnen we daar niet een mooie regel voor bedenken? Dat zou wel zeer behulpzaam zijn denk ik.