fördjupad Ruby: Modules & Include vs. Extend

Ruby ger en konstruktion som kallas en Module som är ungefär som en tunn klass. Först kan Ruby devs titta på moduler som en” skräplåda ” med kod som bara kastas runt och används för att organisera filer, men det finns en metod för denna galenskap. Ruby-klassen Class ärver från Module och lägger till saker som instantiation, egenskaper, etc – allt du normalt skulle tro att en klass skulle ha. Eftersom Module är bokstavligen en förfader till Class, betyder det att moduler kan behandlas som klasser på vissa sätt.

viktigast att förstå är hur Ruby ancestor-kedjan fungerar. Liksom alla OOP-språk Stöder Ruby arv. När du ärver från en klass läggs superklassen till i din förfaderkedja. Du kan se förfäderna i vilken klass som helst genom att ringa ancestors på den:

class Foo < BarendFoo.ancestors#=> 

Som nämnts kan du hitta Module i matrisen Class.ancestors.

När du include en modul i din klass läggs modulen till i klassens förfaderkedja – precis som en klass. Detta gör include bara en form av arv, det finns inget speciellt med det.

module Barendclass Foo include BarendFoo.ancestors#=> 

alla metoder i Bar läggs till i Foo som instansmetoder. Eftersom Bar finns i kedjan kan du till och med ringa super från den för att ringa metoder ovanför den i kedjan, oavsett om de definieras på moduler eller klasser.

class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world

Även om Bar är en modul, super fortfarande ringer upp kedjan och så Baz#hello kallas också. Det är värt att notera att Bar läggs till förfaderkedjan framför Baz. När en modul ingår, läggs den alltid direkt ovanpå den inklusive klass. Detta kan bli förvirrande när du lägger till flera moduler, eftersom de ingår i” omvänd ” ordning:

class Foo include A include BendFoo.ancestors#=> 

När A ingår, infogas den direkt ovanför Foo. Men när B ingår, sätts den också in direkt ovanför Foo, så det slutar landa innan A.

include vs extend

include är lätt att förstå, det lägger modulens metoder som instans metoder för att det är inklusive klass. Du kan tänka dig att extend gör samma sak, men istället lägger till metoderna som klassmetoder.

module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'

prepend

förutom att inkludera/förlänga, Ruby 2.0+ lägger till prepend metod. prepend liknar include, men lägger istället in modulen före inkluderingsklassen i arvskedjan.

class Foo include Bar prepend BazendFoo.ancestors#=> 

i Ruby kan du öppna någon klass igen och omdefiniera metoderna på den-det verkar inte vara användbart att åsidosätta metoder på en klass med en prepended modul i motsats till att omdefiniera dem. Där prepend kommer till nytta är när du fortfarande behöver den ursprungliga implementeringen av metoden, eftersom prepended-moduler kan åsidosätta metoder men ändå använda super för att ringa den ursprungliga implementeringen.

Lämna ett svar

Din e-postadress kommer inte publiceras.