http://esiyo.net - uordek.essiyoo.each { |yazi| esiyo.net << yazi }

Ruby’de Modül Yapısı - 2

26.12.2006, yazan Tankut ŞENTÜRK

Merhabalar bir önceki yazımızda module kavramına değinmiş ve basit anlamda kullanımını işlemiş be bu yazımızda da çok güzel bir mudule mixin örneği olduğunu söylemiştik. Şimdiki yazımızda Module kavramını daha da derinden işleyeceğiz.

Öncelikle module ile class arasındaki farktan bahsedelim. Evet fark diyorum çünkü sadece bir-iki küçük fark var. Elbette temelde birbirinden çok farklı yapılar ama, son kullanıcı yani bizler için aralarındaki fark at ile deve değil.
- class'ların anlık kopyaları olabilir, module'lerin olamaz.
- class'ların içerisinde module'ler olamaz, module'lerin içerisinde class'lar olabilir.
- class'lar ve içlerindeki öğeler protected, private gibi erişim denetleyici özelliklere sahip olabilirler, module'ler sahip olamazlar, tüm öğeleri public'tir.

Class ile module'ler arasındaki temel farkları inceledikten sonra module mixin kavramı ile ilgili konuşmalarımıza başlayabiliriz. Yazının geri kalanında kullanılacak bir hatırlatma yapmak isterim.

class LogClass
    NAME = "Default Class"
   
    def LogClass.create # static create method
        printf "%s LogHelper.create\n", NAME
    end

    def create # instance create method
        printf "%s LogHelper.create\n", NAME
    end
end

Yukarıda belirtildiği gibi, "LogClass.create" methodu ile "create" methodu birbirinden farklıdır. "LogClass.create" methodu durağan (static, kullanmak için bir nesneye ihtiyaç duyulmaz.) bir method iken, "create" methodu kullanmak için "LogClass.new" methodu ile yeni bir "LogClass" yaratmalı ve bu nesne üzerinden "create" methoduna erişmeliyiz.

Bu bilgilerin ışığında aşağıdaki gibi tanıtılmış olan bir LogHelper modülünde

module LogHelper
    NAME = "Default Logger"

    def LogHelper.create
        printf "%s LogHelper.create\n", NAME
    end
    ....
end

tüm methodların durağan (static) olduğunu söyleyebiliriz.

Peki "module mixin" kullandığımızda sadece durağan (static) methodlar için mi kullanabileceğiz, elbetteki hayır. "Module mixin" özelliğini tüm durumlar için kullanabiliriz.
Hemen örneğimizi verelim;

module LogHelper # Module mixin işemi için
    NAME = "Default Logger"

    def error # LogHelper'da dinamik bir method
        printf "%s #{self}.error\n", NAME
        @operationList.push("error")
    end

    def self.myTest # LogHelper'da durağan bir method
        printf "%s #{self}.myTest(Static)\n", NAME
    end
   
    def myTest # LogHelper'da dinamik bir method
        printf "%s #{self}.myTest(Instance)\n", NAME
        LogHelper.myTest # LogHelper'daki static method çağrılir.
        @operationList.push("myTest")
    end
end

class LogClass
    # LogHelper modülü sanki copy-paste edilmiş gibi bu sınıfın içerisinde yer alir.
    # LogHelper üzerinden static olmayan methodlar alınır.
    include LogHelper
    attr_reader :operationList
   
    def initialize # LogClass'in yapıcısı
        @operationList = Array.new
    end
   
    def ownMethod # LogClass'in dinamik bir methodu
        printf "%s #{self}.OwnMethod\n", NAME
        @operationList.push("OwnMethod")
    end
end

# İşlemleri biraz daha karmaşıklaştırmak için ayrı bir modül içerisinde program yazılmiştır.
module LogProgram
    logClass = LogClass.new # Yeni bir LogClass yaratılır.
    logClass.ownMethod # LogClass'ın methodu cağrılır.
    logClass.error # LogClass üzerinden LogHelper'in methodu çağrilir. Ama LogClass'in değişkenleri kullanılır.
    logClass.myTest # error'u çağırmaktan tek farkı, myTest içerisinde static olan LogHelper.myTest'in cağırılmasıdır.
   
    LogHelper.myTest # Static olan LogHelper.myTest çağrılır.
   
    # Bu işlem için Ruby bize "warning: toplevel constant Y referenced by X::Y" uyarısını verir.
    # Uyarı vermesinin nedeni işlemi garip ve tehlikeli şekilde yapıyor olmamızdır.
    LogClass::LogHelper.myTest
   
    # Yapilmiş işlemler ekrana yazdırılır.
    puts logClass.operationList
end

Yukarıda program işlendikten sonra ekrana;
Default Logger #.OwnMethod
Default Logger #.error
Default Logger #.myTest(Instance)
Default Logger LogHelper.myTest(Static)
Default Logger LogHelper.myTest(Static)
Default Logger LogHelper.myTest(Static)
OwnMethod
error
myTest
module02.rb:41: warning: toplevel constant LogHelper referenced by LogClass::LogHelper

çıktısını vermektedir.

Sonuç olarak mudule mixin kavramı, yazdığımız modülün static methodlarını copy-paste etmişcesine kullandığımız sınıfın içerisine kopyalanması gibi düşünebiliriz. Bu özellikle 'multiple inheritance' kavramının eksikliği ustaca giderilmiştir.

Umarım bu yazıyı okuduktan sonra, Rails üzerinde yazdığınız uygulamara daha farklı yaklaşırsınız, işin aslı ruby on rails alt yapısı, büyük ölçüde bu felsefe ve özelliği kullanan bir yapıdır.

Kolay gelsin :)

Bağlı olduğu kategoriler; Bilgisayar, Ruby (Ruby on Rails)

Yaz aklındakini, çekinme :)

Lütfen: Yorumunuzun değerlendirilmesi ve yayınlanması uzun sürebilir. Yorumunuzu tekrar göndermeniz için bir neden yoktur, inanın tüm yorumları yayınlıyorum. Bazıları hariç :).