8. Klassen en modules
8.1 Kan een klasse definitie worden herhaald?
Een klasse kan meerdere keren worden gedefinieerd. Iedere definitie wordt bij de vorigen gevoegd. Word een methode geherdefineerd dan zijn de vorigen overridden en niet meer toegankelijk.
8.2 Zijn er klasse veriabelen?
Vanaf Ruby 1.5.3, ja. Een variabele voorafgegeaan door twee at signs (@@) is a klasse variabele die zowel beschikbaar is voor instance en klasse methodes.
class CountEm |
Eerdere versies van Ruby hadden geen klasse variabelen. Echter
container klassen (Array
, Hash
, etc)
toegekend aan een klasse constante kunnen gebruikt worden om het zelfde
effect te krijgen. Dit voorbeeld gebruikt een array, andere mensen
gebruiken liever een hash.
class Foo |
Dit houd het aantal keer bij dat foo
is aangeroepen
over alle instanties van de klasse Foo heen
.
8.3 Wat is een klasse instance variabele?
class Foo |
(1) is een klasse instance variable, en (2) is een gewone
instance variable (die, omdat die niet is geninitialiseerd, de
waarde nil
heeft). (2) hoort bij een instantie van de
klasse Foo
, en (1) hoort bij het klasse object Foo
,
wat een instance is van de klasse Class
. (phew!)
Het is niet mogelijk om klasse instantie variabelen te benaderen vanuit instance methodes.
8.4 Wat is een singleton methode?
Een singleton methode is een instance methode die hoort bij een specifiek object.
Je maakt een singleton methode door een object op te nemen in de definitie:
class Foo |
Singleton methodes zijn handig als je een methode wil toevoegen aan een object en het maken van een nieuwe subklasse niet wenselijk is.
8.5 Heeft Ruby klasse methodes?
Een singleton methode van een klasse object is word een klasse methode genoemd. (Eigenlijk word de klasse methode gedefinieerd in de metaklasse, maar dat is voor het grootste deel transparant). Je kan het ook zo zien dat een klasse methode een methode is wiens receiver een klasse is.
Het komt er op neer dat je een klasse methode kan aanroepen zonder dat je instanties van die klasse als receiver nodig hebt.
We maken een singleton methode van de klasse Foo
:
class Foo |
In dit voorbeeld is Foo.test
een klasse methode.
Methodes die zijn gedefinieerd in de klasse Class
kunnen door iedere klasse als klasse methode worden gebruikt(!)
8.6 Wat is een singleton klasse?
Een Singleton klasse is een anonieme klasse die is gecreeerd door een klasse te subklassen die hoort bij een bepaald object. Zij vormen een andere manier om de functionaliteit van een bepaald object uit te breiden.
Neem het simple Foo
:
class Foo # -> hello<<7>>nil |
Stel dat we het nodig vinden om klasse functionaliteit toe te voegen voor deze ene instantie:
class << foo |
We hebben nu foo
aangepast zonder Foo
te
veranderen.
8.7 Wat is een module functie?
Een module functie is een private, singleton methode
gedefinieerd in een module. Het is in zoverre gelijk aan een klasse methode, dat het kan
worden aangeroepen met de theModule.method
notatie:
Math.sqrt(2) # -> 1.414213562 |
Echter , omdat modules als mixin in klasses kunnen worden opgenomen,
kunnen module functies ook zonder de prefix worden gebruikt (op die
manier worden al de Kernel
functies voor objecten
beschikbaar gemaakt):
include Math |
Gebruik module_function
om van een functie een module
functie te maken.
module Test |
8.8 Wat is het verschil tussen een klasse en een module?
Modules zijn verzamelingen van methodes en constanten. Ze kunnen geen instanties genereren. Klasses kunnen instanties genereren (objecten) en per instantie een aparte staat vasthouden (instance variabelen).
Modules kunnen als mixin in klasses en andere modules worden opgenomen. De constanten and methodes van de mixin vermengen zich met die van de klasse zelf en breiden op die manier de functionaliteit van de klasse uit. Klasses kunnen niet als mixin gebruikt worden.
Een klasse kan erven van een andere klasse, maar niet van een module.
Een module kan nergens van erven.
8.9 Kan je een modules subklassen?
Nee. Echter, een module kan worden opgenomen in een andere klasse of module om zo multiple inheritance te simuleren (de mixin faciliteit).
Dit genereerd geen subklasse (wat overerving zou vereisen), maar
zorgt voor een is_een?
relatie tussen de klasse en de
module.
8.10 Geef eens een voorbeeld van een mix-in?
De module Comparable
verschaft een diverse
vergelijkings operators (<, <=, >, between?
etc.).
Het definieerd deze in termen van aanropen naar de algemene
vergelijkings methode, <=>
. Echter <=>
word
er niet in gedefinieerd.
Stel dat je een klasse wil maken waarin vergelijkingen gebaseesd zijn op het aantal poten van een dier:
class MyClass |
Het enige dat MyClass
moet doen is zijn eigen
semantiek
voor de operator <=>
definieeren en de Comparable
module als mix-in gebruiken. De methodes van Comparable
zijn dan niet meer te onderscheiden van die van MyClass
en
je klasse heeft ineens meer functionaliteit. Omdat de Comparable
module door veel klassen word gebruikt deelt je klasse een consistente
en goed begrepen semantiek.
8.11 Waarom zijn er twee manieren om een klasse methode te definieeren?
Je kan een klasse methode definieeren in de klasse definitie en je kan klasse methode definieeren in het top level?
class Demo |
Er is maar een belangrijk verschil tussen deze twee. In de klasse
definitie kan je rechtstreeks aan de klasse constanten refereren omdat
deze binnen de scope vallen. In het top level moet je de Class::CONST
notatie gebruiken.
8.12 Wat is het verschil tussen load
and require
?
load
laadt een Ruby programma (*.rb
) en
voert dit uit.
require
laadt ook Ruby programma's maar laadt tevens
binaire Ruby extension modules (shared libraries of DLLs). Verder
zordgt require
ervoor dat een functie nooit meer dan een keer wordt geladen.
8.13 Wat is het verschil tussen include
and extend
?
include
gebruikt een module als mix-in voor een klasse
of andere module. Methodes van die module worden aangeroepen met de
functie-stijl (zonder receiver).
extend
word gebruikt om een module op te nemen in een
object (instantie). Methodes in de module worden methodes in het
object.
8.14 Wat betekent self
?
self
is de actieve receiver -- het object waarvan de
methode word uitgevoerd. Een functie aanroep in functie-stijl
impliceerd self
als de receiver.
8.15 Waarom kan ik geen variabelen laden vanuit een apart bestand?
Stel dat file1
het volgende bevat:
var1 = 99 |
en dat een ander bestand het laadt:
require 'file1' |
Je krijgt een foutmelding omdat load
en require
ervoor zorgen dat locale variabelen worden opgeslagen in een aparte
naamloze namespace, waardoor ze in feite worden weggegooid. Dit
is
bedoeld om te voorkomen dat je code vervuild word.