17 Module ve Mixin 17.1 Module nedir? En genel anlamıyla, modül (module), programın iyi düzenlenmesini sağlayan yapı taşlarıdır. modül, fiziksel olarak düzenlenmiş ve farklı dosyalara yazılmış Ruby kodlarının lojik olarak biraraya getirilmesini sağlar. Bir modül değişkenler, yürütülebilir kodlar, fonksiyonlar, sınıflar içerebilir. İçerdiği öğeler farklı dosyalarda, farklı fiziksel ortamlarda olabilir. Bir modül bir programa çağrılınca, o modülün içindekiler, sanki o programa yazılmış gibi davranırlar. 17.2 Neden Module? Belli bir işi yapmak için metot tanımlamayı öğrendik. Belli nitelikleri ve davranışları olan nesneler yaratmak için de sınıf (class) tanımlamayı biliyoruz. Bunlar programımızın istediğimiz eylemleri yapması için yararlı öğelerdir. Ama, bir programda yazdığımız metodu ya da sınıfı başka bir programda kullanmak istersek, şu ana kadar, kes-yapıştır yöntemi dışında bir yol bilmiyoruz. Çok sayıda metot ve sınıf kullanan büyük programlarda kes-yapıştır yöntemi ideal bir yöntem değildir. Onun yerine, önceden yaratılan metotları ve sınıfları kullanmanın daha iyi bir yolu olmalıdır. Modül (module) bu kolaylığı sağlar. Sınıfları incelerken, Bir Ruby sınıfının en çok bir tane üst sınıfı olabileceğini, ama istenildiği kadar alt sınıfları olabileceğini söylemiştik. Tabii, alt sınıfların da başka alt sınıfları olabilir. Böylece atadan oğula giden sa- 216 BÖLÜM 17. MODULE VE MIXIN çaklar oluşur. Ancak, uygulamada bir sınıfta, daha önce başka yerde tanımlanmış olan metotları çağırıp kullanmak gerekir. Tabii, kullanılacak metotların tekrar sözkonusu sınıfta yeniden tanımlanması mümkündür. Ama bu yol çok sayıda tekrarı getirir ve nesne tabanlı programlamanın özüne aykırı düşer. Dolayısıyla, daha önce tanımlanmış metotları ve sabitleri tekrar tekrar tanımlamadan kullanmanın bir yolu bulunmalıdır. C++ dilinde bu sorun, bir sınıfın birden çok üst sınıfı olmasına izin verilerek aşıldı. Ancak, bir sınıfın üst sınıflarından ve alt sınıflarından oluşan atalar ve oğullar, karmaşık bir düğümler kümesi yarattı. Bu yapı, C++ programcısına yeni zorluklar getirdi. Java dili, bu sorunu aşmak için arayüzleri (interface) kullandı. Java’nın bulduğu yöntem C++ dilinde karşılaşılan zorlukları kolayca aştığı için geniş kabul gördü. Ondan sonra ortaya çıkan nesne tabanlı diller, sorunu benzer yöntemlerle çözme yoluna gittiler. Ruby’nin getirdiği çözüm yolu, düşünce olarak Java ve Python’un izlediği yola benzer. Ama teknik ayrıntılarda büyük ayrılıklar vardır. 17.3 Module Ruby’nin yukarıda açıkalanan probleme çözümü module yapısı ile verildi. Modül (module) sınıflar, metotlar ve sabitler içeren bir birimdir. Tanımı sınıf tanımına benzer. Aslında her sınıf bir module’dir. Modül içinde anlık metotlar (instance methods) ve module metotları olabilir. Anlık metotlar, sınıf içindeki anlık metotlar gibi davranırlar. Onlara ancak bir nesne içinden erişilebilir. Dolayısıyla modülün bir nesne içine konulması gerekir. mixin denilen bu eylemi biraz sonra ele alacağız. Oysa module metotlarını çağırmak için modülü içeren bir nesne üretilmesi gerekmez. Modüllerin iki önemli yararı vardır: 1. Her modülün kendi aduzayı vardır. Aduzaylarını bilgisayarımızın kayıt ortamında yarattığımız dizinlere benzetebiliriz. Modüller, büyük programlarda aynı adlı nesnelerin çakışmasını önler. Örneğin aynı adı alan iki metot farklı modüller içine konulursa, her biri kendi modülü içindeki rolünü oynar; sonra yazılan öncekinin yerini almaz. Bir modül içindeki öğelere (sabit, metot, sınıf) ancak o modül içinden erişilebilir. [Bir Dizin içindeki dosyalar imiş gibi düşününüz] 2. Modüller başka sınıfların nesneleri içine konulabilir; yani modüller 17.3. MODULE 217 mixin uygulamasına izin verirler (Bunu biraz sonra açıklayacağımızı söylemiştik). Her metot bir modüldür. Her sınıf bir modüldür. Modüller sabitler ve metotlar içerir. Modüller aduzayı olarak kullanılır. Modül bildirimi için sözdizimi şöyledir: Liste 17.1. 5 module Ad deyim1 deyim2 .... end 17.3.1 Module Tanımı Liste 17.2. 5 module Kurum d e f selam p u t s " Merhaba " end end Modül sabitleri sınıf sabitleri gibidir; adları büyük harfle başlar. Modül metotları da sınıf metotları gibi tanımlanır. Ama modüller iki tür metot içerebilir: Anlık metot, module metodu. Program 17.1. module RuhHali IYIMSER = " i y i m s e r i m " KOTUMSER = " kötümserim " 5 10 d e f selam r e t u r n " Ben #{IYIMSER } . Sen n a s ı l s ı n ? " end d e f RuhHali . selam r e t u r n " Ben #{KOTUMSER} . Sen n a s ı l s ı n ? " end end 218 15 BÖLÜM 17. MODULE VE MIXIN p u t s ( " S a b i t ça ğ ı r ma : p u t s ( RuhHali : : IYIMSER) RuhHali : : IYIMSER" ) p u t s ( " Module Metodu ça ğ ı r ma : p u t s ( RuhHali . selam ) RuhHali . g r e e t " ) Açıklamalar: • Program 17.1, RuhHali adlı bir modül tanımlıyor. • Bu modül IYIMSER ve KOTUMSER adlı iki sabit ile selam adlı anlık bir metot ve RuhHali.selam adlı bir module metodu içeriyor. Öntakısız yazılan selam metodu anlık (instance) bir metottur. Modül adını öntakı olarak alan RuhHali.selam metodu ise bir module metodudur. • Bu modülü bir sınıfa dönüştürmek için ilk satırındaki module yerine class yazmak yeterlidir. • Tanımları benzer olmasına karşılık, sınıf ile module arasında önemli bir fark vardır: Sınıflardan nesne üretilebilir. Alt sınıfları tanımlanabilir. Üst sınıftaki özelikler oğullara kalıtsal olarak geçer (inheritance). Oysa, modüllerin nesnesi ve alt modülleri olmaz. Son söylediklerimize bakarak, modüllerin ne işe yaradığı sorusu akla gelebilir. Sınıf gibi tanımlanıyor ama sınıfın nitelikleine bile sahip değilse, neden modül ile uğraşıyoruz? Bu sorunun yanıtını, aslında bu bölümün girişinde verdik. Ruby’nin Class sınıfının önemli modülleri vardır. Math modülüne hepimiz aşinayız. Math modülünün sabitlerini ve metotlarını izinsiz kulanırız. Örneğin, PI sabiti, sqrt metodu, trigonometrik ve loharitmik fonksiyonlar bunlardandır. Ruby’de Class sınıfının verdiği ikinci önemli modül Kernel adını alır. Kernel modülü şimdiye dek kullandığımız print, puts, gets gibi metotları bize sunan modüldür. Bunların metotlarını listelemek için methods metodunu kullanabilirsiniz: Kernel.methods irb etkileşimli kabuğunda yazacağınız bu komut size Kernel modülünün bütün metotlarını verecektir. Sabitler Aslında sabitler birer değişkendir; tek farkları değerlerinin değişmiyor oluşudur. Çok istiyorsanız sabitin değerini elbette değiştirebilirsiniz; ama o zaman Ruby sizi uyaracaktır. 17.3. MODULE 219 Modül’den Sabit Çağırma Modül’den sabit çağıran sözdizimi örneği: aaa modül, ccc çağrılacak sabit ise aaa::ccc yazılır. Modül_adından sonra ard arda iki tane üst üste iki nokta (::) yı izleyen sabit_adı. Örnek 17.1’de RuhHali::IYIMSER deyimi, modülden IYIMSER adlı sabiti çağırır. Modül’den Metot Çağırma Modül’den module metodu çağıran sözdizimi şöyledir: aaa modül, mmm çağrılacak metot ise, aaa.mmm yazılır. Modül_adı, nokta bağlacı (.), metot_adı. Örnek 17.1’deki RuhHali.selam modül metodunu çağırmak için RuhHali.selam deyimi yeterlidir. Ama, anlık metot için, puts (selam) deyimi iş yapmayacaktır. O metodu ancak RuhHali modülünü içeren bir nesne içinden çağırabiliriz. include Bir sınıftan üretilen nesne içine bir modülü çağırmak için include (module_adı) deyimi yeterlidir. Bu deyimden sonra modül içindeki her şey nesne içine girecektir. Örnek 17.1’deki selam anlık metodunu çağırmak için puts (selam) deyimi yeterlidir. 220 BÖLÜM 17. MODULE VE MIXIN 17.4 mixin Aslında, yukarıda yaptıklarımız mixin işlemini gerçekleştirmiştir. Özetlersek, include metodu ile bir modülü bir nesne içine koymuş oluruz. O andan itibaren, modülün bütün öğeleri nesnenin olur; onlara nesne içinden adlarıyla erişilebilir. Program 17.1’ye puts (selam) deyimini ekleyiniz. irb’nin 1 u n d e f i n e d l o c a l v a r i a b l e o r method ‘ selam ’ f o r main : O b j e c t ( NameError ) hata uyarısını verdiğini göreceksiniz. Bunun nedeni, modül içindeki anlık metoda doğrudan erişmek istememizdir. Anlık metotlara ancak bir nesne içinden erişilebilir. Öyleyse, önce bir sınıf tanımlayalım, o sınıfın bir nesnesi içine include metodu ile modülü çağıralım. Ondan sonra modülün selam adlı anlık modülüne erişebiliriz. 17.5 Aduzayları 17.6 index Aduzayı kavramı başka dillerde de kullanılır. Birbirleriyle ilgili program öğelerinin adlarını mantıksal (logic) olarak bir araya getiren bir yapıdır. Ruby’de her module bir aduzayı belirler. Module öğeleri kendi aralarında iletişim kurabilirler; ama yapı dışarıya kapalıdır. Sanki çevresi kalın duvarlarla çevrilidir. Dışarıdan modülün öğelerine erişim için özel yöntemler gerekir. Onları biraz sonra ele alacağız. Örnek 17.1 ile 17.2 ile tanımlanan Daire ve Kare modüllerinin içerdiği anlık alan_bul metodu ile cevre_bul module metotlarının adları aynıdır. Ama bunlar farklı aduzaylarında yer aldığı için çakışmazlar. Öncekiler dairenin alanı ve çevresini bulurken, sonrakiler karenin alan ve çevresini bulur. Aşağıda iki modül bildirimi yapılmıştır. Her iki modülde yer alan aynı adlı metotlar, birbirleriyle çakışmaz, kendi modülleri içinde varlıklarını ve işlevlerini sürdürürler Örnek 17.1. #! / u s r / b i n / ruby 221 17.6. INDEX 4 module D a i r e PI = 3 . 1 4 1 5 9 2 6 5 4 R = 3 d e f alan_bul a l a n = PI ∗ (R∗ ∗ 2 ) end 9 d e f Daire . cevre_bul c e v r e = 2∗ PI ∗R end end 14 puts ( " Dairenin y a r ı ç a p ı n ı ç a ğ ı r : p u t s ( D a i r e : : R) 19 1 D a i r e : : R" ) p u t s ( " D a i r e n i n ç e v r e s i n i bulan module metodunu ç a ğ ı r : _bul " ) puts Daire . cevre_bul Daire . ce vre \ /∗ 3 18.849555924 ∗/ Örnek 17.2. 1 #! / u s r / b i n / ruby module Kare KENAR = 3 d e f alan_bul a l a n = KENAR∗KENAR end 6 11 16 d e f Kare . c e v r e _ b u l c e v r e = 4∗KENAR end end p u t s ( " Karenin b i r k e n a r ı : p u t s ( Kare : : KENAR) Kare : : KENAR" ) p u t s ( " Karenin ç e v r e s i n i bulan module metodunu ç a ğ ı r : _bul " ) p u t s Kare . c e v r e _ b u l 1 /∗ 3 12 ∗/ Kare . c e v r e \ 222 BÖLÜM 17. MODULE VE MIXIN Module Çağırma : include 17.7 include Bir modülü bir sınıf içine çağırmak için include anahtar sözcüğünü kullanırız. Çağrılan modülün her şeyi sınıfın öğesi olur. Liste 17.3. 1 6 c l a s s Personel i n c l u d e Kurum end selma = P e r s o n e l . new selma . selam 17.7.1 Modül’den Nesne Üretilemez Program 17.2 ile tanımlanan Kurum modülünden new operatörü ile bir nesne yaratmayı deneyelim. Derleyici aşağıdaki uyarıyı vererektir. uyarı, modulün new metodunun olmadığını; dolayısıyla onun bir nesnesinin yaratılamayacağını söylüyor. Kurum.new #=> undefined method ’new’ for Kurum:Module 17.8 Sınıf ile Modül Karşılaştırması 17.9 Çağrı Yöntemleri load, require, include, extend 17.10 load 17.11 require 17.12 include 17.13 extend Hepsi aynı işleve sahipmiş gibi görünüyor. 223 17.13. EXTEND Tablo 17.1: Sınıf ile Module Karşılaştırması üretim (instantiation) kullanım üst sınıf öğeleri metotlar kalıtım sınıf (class) module üretilebilir üretilemez nesne yaratılır module metotlar, sabitler, değişkenler sınıf metodu, anlık metot eylemleri kalıtsal alır/verir mixin, aduzayı object metotlar, sabitler, sınıflar module metodu, anlık metot kalıtım yok sınıfta ve başka modülde include metodu ile içerilebilir üretilen modül genişleyebilir: ’singleton’ içerme içerilemez genişleme extend metodu ile genişleyemez; kalıtım ile genişleyebilir load : Bir dosya içeriğini yükler. load ’deneme.rb’ Aynı dosya birden çok kez yüklenebilir (load). Sonuncu etkin olur. require : Bir dosyadan seçilenleri alır require ’deneme’ Birden çok kez seçim yapılabilir. İlk yapılan seçim etkindir. include : Modülü, çağıran sınıftan üretilen nesne içine alır ve nesnenin öğeleri gibi kullanılmasını sağlar. include deneme extend : Sınıfın metotlarını ekleyerek onu çağıran modülü genişletir. extend deneme • Sınıf, modüldeki metoda sahipse, modül sonradan çağrılmış olsa bile sınıfın metodu etkin olur. Başka bir deyişle, sınıf daha baskındır. • Çağrılan iki modülde aynı adlı metot varsa, son çağrılandaki etkin olur, önce çağrılan modüldeki ihmal edilir. • Bir modül iki kez çağrılırsa, ilk çağrı etkin olur, sonraki çağrı yok sayılır. 224 BÖLÜM 17. MODULE VE MIXIN 17.14 Uygulamalar Liste 17.4. 4 c l a s s Soyut include A include B include A end # => e t k i s i z d i r ; i l k ç a ğ r ı g e ç e r l i d i r Liste 17.5. 5 10 15 20 25 30 module A d e f a1 p u t s ’ a1 ç a ğ r ı l d ı ’ end end module B d e f b1 p u t s ’ b1 ç a ğ r ı l d ı ’ end end module C d e f c1 p u t s ’ c1 ç a ğ r ı l d ı ’ end end c l a s s Test include A include B include C def display puts " Modüller ’ included ’ i l e end end çağrıldı " o b j e c t=Test . new object . display o b j e c t . a1 o b j e c t . b1 o b j e c t . c1 Array sınıfının local_variables metodu, yerel değişkenleri listeler: Liste 17.6. 2 # e n c o d i n g UTF−8 module ModuleM m1 , m2 = 4 17.14. UYGULAMALAR 225 p u t s " module i ç i n d e " puts l o c a l _ v a r i a b l e s 7 12 17 end d e f method1 v, w = 3 p u t s " method i ç i n d e " puts l o c a l _ v a r i a b l e s end c l a s s Some x, y = 2 puts " c l a s s i ç i n d e " puts l o c a l _ v a r i a b l e s end 22 method1 t1 , t 2 = 7 27 puts " I n s i d e t o p l e v e l " puts l o c a l _ v a r i a b l e s Program 17.2. 2 module Meyveler @@meyve = ’ k i r a z ’ def s e l f . set (x) @@meyve = x end 7 def s e l f . get @@meyve end end 12 p T. get T . s e t ( ’ elma ’ ) p T : : get #=> ’ k i r a z ’ #=> ’ elma Program 17.3, bir module içindeki anlık değişkene bir sınıf içinden erişimi gösteriyor. Program 17.3. module Kimlik 5 a t t r _ a c c e s s o r : kimlik_no def i n i t i a l i z e @kimlik_no = 123 end end 226 10 15 20 BÖLÜM 17. MODULE VE MIXIN c l a s s Personel i n c l u d e Kimlik def i n i t i a l i z e super end d e f kimlik_no_yaz p u t s @kimlik_no end end m = P e r s o n e l . new m. kimlik_no_yaz #=> 123 Program 17.4. # e n c o d i n g UTF−8 3 8 13 module K e d i l e r sa y = 2 c l a s s Kedi def ses_ver p u t s " Miyauuu . . . " end d e f yemek puts " . . . " end d e f kuyruk_oynat p u t s " s i n i r l e n i n c e kuyruğumu o y n a t ı r ı m ! " end 18 23 d e f pençe_at p u t s " Olmaz , c a n ı n yanar ! " end end end x = 5 t e k i r = K e d i l e r : : Kedi . new t e k i r . kuyruk_oynat i f x >= K e d i l e r : : s a y Program 17.5. #e n c o d i n g : u t f −8 3 module Hafta ILK_GUN = " Pazar " d e f Hafta . ayda_hafta p u t s " B i r ayda d ö r t h a f t a v a r " end 17.14. UYGULAMALAR d e f Hafta . s e n e d e _ h a f t a p u t s " B i r y ı l d a 52 h a f t a v a r " end 8 end 13 18 23 28 c l a s s On_sene i n c l u d e Hafta s e n e _ s a y i s i =10 def ay_sayisi p u t s Hafta : : ILK_GUN s a y i =10∗12 puts s a y i end end d1=On_sene . new p u t s Hafta : : ILK_GUN Hafta . ayda_hafta Hafta . s e n e d e _ h a f t a d1 . a y _ s a y i s i 227
© Copyright 2024 Paperzz