Module ve Mixin 17.1 Module nedir? 17.2 Neden Module?

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