1.4.1.7. fejezet, Metódusok
Metódus elnevezés
A metódusok elnevezése általában végig kisbetűs, de ez nem kötelező, csak ajánlott. Ha nagy betűvel kezdenénk egy metódusnevet, akkor az már egy konstans is lehet. Ezért ott egyértelműsíteni kell zárójelekkel, hogy metódushívás történik, például: a.Konst1().
Osztály és objektum metódusok
Korábban említésre került az osztály metódus és a példánymetódus közti különbség.
class MyClass def MyClass.classMethod puts( "This is a class method" ) end def instanceMethod puts( "This is an instance method" ) end end
Az osztály metódusok objektum példányosítás nélkül használhatók. Ezek elérik az osztály tulajdonságokat(@@), az osztály-objektum tulajdonságokat (@) az osztálymetódusokon keresztül, viszont nem érik el a példány tulajdonságokat (@). Egy lényeges megállapítás van az előbbiekben, hogy az osztály is egy objektum a ruby-ban. Ezért az osztály metódusokban is elérhető egy osztály-objektum tulajdonsága. Kicsit nyakatekerten hangzik, de ez van, és talán később találunk rá jobb példát.
Osztály és objektum tulajdonságok
Ugyanígy létezik osztály és objektum tulajdonság. Az osztály tulajdonságot @@ előjelekkel, az objektum tulajdonságot egy @ előjellel jelöli a ruby.
class Thing @@num_things = 0 @name @desc def initialize( aName, aDescription ) @@num_things +=1 @name = aName @desc = aDescription end end t=Thing.new("alma","bagoly") p(t)
Az initialize metódus ős osztálybeli megfelelőjét csak akkor hívjuk a, ha definiáltuk ott. Az osztály változóknak értéket kell adni. Ez lehet közvetlen vagy közvetett értékadás. Példányszámláló esetén például inicializáláskor növelhetjük a számlálót.
class Obj @mySQL attr_accessor :mySQL @@otherSQL def initialize(mySQL,otherSQL) @mySQL=mySQL @@otherSQL = otherSQL end def Obj.classMethod1(aStr) return "otherSQL = #{@@otherSQL} #{aStr}" end def get_mySQL(aStr) return "#{@mySQL} #{aStr}" end def Obj.write_classSQL(aSQL) @classSQL=aSQL end def Obj.read_classSQL return @classSQL end end
Metódus fűzés az osztályhoz egy későbbi helyen.
class << Obj def table( aStr ) return "#{@classSQL}, #{aStr}" # Ez olvashatja a @classSQL osztaly tulajdonsagot end def read_otherSQL return "#{@@otherSQL}" # @@otherSQL nincs inicializalva end end
A metódusok hívása:
ob=Obj.new('select * from', "update table") puts(Obj.classMethod1('classMethod1')) # statikus metodus osztaly valtozot hasznalhat puts(ob.get_mySQL("objektum tulajdonsan")) # objektum valtozo hasznalata egy objektumban Obj.write_classSQL("osztaly tulajdonsag") puts(Obj.read_classSQL) # osztaly tulajdonsag puts(Obj.table("osztaly metodus 2")) # statikus metodus nem eri el az osztalyvaltozot puts(Obj.read_otherSQL)
Kimenet:
otherSQL = update table classMethod1 select * from objektum tulajdonsan osztaly tulajdonsag osztaly tulajdonsag, osztaly metodus 2 c:\wamp\bin\apache\Apache2.2.11\cgi-bin>ruby singleton.rb otherSQL = update table classMethod1 select * from objektum tulajdonsan osztaly tulajdonsag osztaly tulajdonsag, osztaly metodus 2 singleton.rb:29: warning: class variable access from toplevel singleton.rb:29:in `read_otherSQL': uninitialized class variable @@otherSQL in Object (NameError) from singleton.rb:39:in '<main>'
A fenti példában a classSQL osztálymetódust és az osztály-objektum tulajdonságot érdemes megfigyelni.
class O2 < Obj def initialize(mySQL,otherSQL) super end end
Leszármazott osztály sem éri el az osztály-objektum tulajdonságot.
ob2=O2.new("insert into classes", "create table new") puts(O2.read_classSQL) puts(O2.classMethod1('O2.classMethod1'))
Kimenete:
# ures sor, nincs classSQL ertek inicializalva otherSQL = create table new O2.classMethod1
Miért is készítenénk osztály metódusokat? Nézzük meg erre válaszként a File osztályt. Tele van osztály metódussal.
fn = 'file_methods.rb' if File.exist?(fn) then puts(File.expand_path(fn)) puts(File.basename(fn)) puts(File.dirname(fn)) puts(File.extname(fn)) puts(File.mtime(fn)) puts("#{File.size(fn)} bytes") else puts( "Can't find file!") end
new metódus, vagy initialize
A new metódus az osztály konstruktora. Ez egy osztálymetódus, és miután elkészült az objektum, meghívja a példány initialize metódusát, ha van ilyen. Kerüljük a new metódus felüldefiniálását. Emlékezzünk csak arra, hogy minden metódus visszatérési értéke az utoljára végrehajtott kifejezés. Vagyis az alábbi kód eredménye egy String objektum "HELLO WORLD" tartalommal, a MyClass objektum helyett
class MyClass def initialize( aStr ) @avar = aStr end def MyClass.new( aStr ) super @anewvar = aStr.swapcase end end ob = MyClass.new( "hello world" ) puts( ob ) puts( ob.class )
Objektum egyedi metódusok
Statikus metódusnál osztálynevet használtunk előtétként, singleton metódusnál objektum változót használunk.
class Creature def initialize( aSpeech ) @speech = aSpeech end def talk puts( @speech ) end end cat = Creature.new( "miau" ) farkas = Creature.new( "vau" )
Mondjuk, hogy egy farkas teliholdnál ugatás helyett vonyít. Ezt az objektum metódussal érhetjük el.
def farkas.vonyitas if TELIHOLD then puts( "How-oo-oo-oo-oo!" ) else talk end end
Egy újabb kutya objektumnál nem találunk vonyitas metódust.
Ha kíváncsiak vagyunk a singleton metódusok listájára, rákérdezhetünk pl. az IO osztályban találhatókra
p( IO.singleton_methods )
vagy a Creature osztályból készített farkas objektumunkra:
p( farkas.singleton_methods )
Minden ruby osztályból készített példány az Object osztály közvetett leszármazottja (ebben van a singleton_methods tömb, aminek az include? metódusával megtudhatjuk, tartalmazza-e a nekünk szükségest), ezen pedig magába foglalja a Class osztályt is. Ellenőrizhetünk egy metódus létezését szimbólum használatával is, az Object.respond_to? metódusával:
if item.respond_to?( :congratulate ) then item.congratulate end
Egyedi osztályok
Tegyük fel, hogy több metódussal, tulajdonsággal szeretnénk bővíteni az objektumunkat. Az egyedi objektum metódus létrehozás helyett bővíthető az objektum egy egész osztályrészlettel.
starprize = MyClass.new( "Star Prize" ) class << starprize def congratulate puts( "You've won a fabulous holiday in Grimsby!" ) end def turnup puts( "Turned up") end end
A létrehozott starprize objektum kibővült két metódussal. Le is kérdezhetjük a p(starprizer.singleton_methods) többel.
Kicsit más felfogása van az egyke osztályhoz képest a singleton class fejezetnek. Tervezési mintákban (design patters) az egyke osztály azt jelenti, hogy a belőle létrehozott példányból egyetlen egy létezik az egész program futása alatt. Az objektumot egy rejtett osztály változóban tárolja, és statikus konstruktor metódus ennek az értékét adja vissza. Tertmészetesen ellenőrzi, hogy üres objektumot ne adjon ki.
Override
Metódus felülírás a leszármazott osztályba lehetséges. A metódus nevével definiált újabb metódus felülírja az eredetit. A felülírt metódus a super.<metódusnév> formában hívható. Az aktuális objektumban lévőre a self.<metódusnév> formában.
A láthatóságról esett már szó. A private, protected, public kulcsszavaról. Metódusokra ezek is érvényesek, hozzá teszem még, hogy ezek a Module osztály metódusai, és nem kulcsszavak, mint megszoktuk.
Egy kibúvót azért enged a ruby a privát metódusok hívására. Ez a send metódus. Első paramétere a metódusnév szimbóluma, a többi az átadandó paraméter. Ha sűrűn használjuk, jobb a metódus láthatóságán változtatni.
ob.send( :privmeth, "hello" )
Egyedi metódus generálást már láttunk, osztályon kívülről. Most ugyan ez történik, osztályon belül:
class MyClass def MyClass.methodA puts("a") end class << self def classMethodB puts("b") end def classMethodC puts("c") end end end
Most megnézzük hogyan ágyazhatunk egymásba metódusokat.
class X def x print( "x:" ) def y print("y:") end def z print( "z:" ) y end end end
Egymásba ágyazott metódusok akkor is elérhetők kívülről - nem csak a metóduson belülről, ahol definiáltuk -, ha elötte lefuttatjuk a definiáló metódust.
ob = X.new ob.x #=> x: Ha ezt elhagyjuk, hibaüzenetként megkapjuk, hogy y és z nem definiált. puts ob.y #=> y: puts ob.z #=> z:y:
- A hozzászóláshoz be kell jelentkezni