Ruby, saf bir nesne yönelimli programlama (OOP) dilidir. Bu, Ruby'de gördüğünüz her şeyin, sayılar, metinler, hatta boolean değerler dahil olmak üzere birer nesne olduğu anlamına gelir. Nesne yönelimli yaklaşım, karmaşık yazılımları daha yönetilebilir, modüler ve yeniden kullanılabilir parçalara ayırmamızı sağlar. Bu makale, Ruby'nin nesne yönelimli doğasını, temel prensiplerini ve pratik uygulamalarını derinlemesine inceleyecektir.
Nesne Yönelimli Programlamanın Temelleri
OOP, temel olarak dört ana prensip üzerine kuruludur: kapsülleme (encapsulation), kalıtım (inheritance), soyutlama (abstraction) ve polimorfizm (polymorphism). Ruby bu prensipleri kendi özgün ve zarif yoluyla uygular.
Sınıflar ve Nesneler:
Ruby'de programlamanın temel yapı taşı sınıflardır. Bir sınıf, nesnelerin blueprint'i veya şablonu gibidir. Nesneler ise bu sınıflardan türetilen somut varlıklardır. Her nesne, kendi verilerine (örnek değişkenleri) ve davranışlarına (metotlar) sahiptir. Sınıflar `class` anahtar kelimesiyle tanımlanır ve nesneler `.new` metoduyla oluşturulur.
Yukarıdaki örnekte `Ogrenci` bir sınıftır ve `ogrenci1`, `ogrenci2` bu sınıftan türetilmiş nesnelerdir. `@ad`, `@soyad`, `@numara` ise bu nesnelerin örnek değişkenleridir.
Kapsülleme (Encapsulation)
Kapsülleme, bir nesnenin iç durumunu dış dünyadan gizleme ve bu duruma kontrollü erişim sağlama prensibidir. Ruby'de bu, örnek değişkenlerine doğrudan erişimi engelleyerek ve onlar üzerinde işlem yapmak için metotlar (getter/setter) sağlayarak gerçekleştirilir. Ruby, bu tür metotları kolayca oluşturmak için `attr_reader`, `attr_writer` ve `attr_accessor` gibi yardımcı metotlar sunar.
Kalıtım (Inheritance)
Kalıtım, bir sınıfın (alt sınıf veya türetilmiş sınıf) başka bir sınıfın (üst sınıf veya taban sınıf) özelliklerini ve davranışlarını miras almasına olanak tanır. Bu, kod tekrarını azaltır ve hiyerarşik bir yapı oluşturulmasını sağlar. Ruby'de kalıtım `<` operatörü ile belirtilir.
`super` anahtar kelimesi, alt sınıftan üst sınıfın aynı adlı metodunu çağırmak için kullanılır. Bu, üst sınıf davranışını genişletmek veya geçersiz kılmak için yaygın bir desendir.
Polimorfizm (Polymorphism)
Polimorfizm, farklı sınıflardan nesnelerin aynı mesaja (metot çağrısı) farklı şekillerde yanıt verebilmesi yeteneğidir. Ruby, `duck typing` adı verilen bir polimorfizm biçimini güçlü bir şekilde destekler. Yani, bir nesnenin belirli bir türden olması yerine, belirli bir metodu uygulaması önemlidir. “Eğer ördek gibi yürüyorsa ve ördek gibi vaklıyorsa, o bir ördektir.” prensibi burada devreye girer.
Yukarıdaki `Hayvan` örneğinde, hem `Kedi` hem de `Kopek` nesneleri `konus` metoduna farklı şekillerde yanıt vererek polimorfizm sergiler.
Modüller (Modules)
Ruby'de modüller, ortak davranışları sınıflara karıştırmak (mix-in) veya isim alanları (namespaces) oluşturmak için kullanılan yapılardır. Modüllerden nesne oluşturulamaz; sadece sınıflara `include` veya `extend` edilerek kullanılırlar.
Metot Görünürlüğü (Method Visibility)
Ruby'de metotların görünürlüğünü kontrol etmek için `public`, `protected` ve `private` anahtar kelimeleri kullanılır.
`self` Anahtar Kelimesi
Ruby'de `self`, mevcut bağlamdaki nesneyi veya sınıfı temsil eder. Bir örnek metodu içinde `self`, metodu çağıran nesneyi işaret eder. Bir sınıf tanımı içinde (metotlar dışında) veya sınıf metotları içinde `self`, sınıfın kendisini işaret eder. Bu, özellikle dinamik programlama ve meta programlama senaryolarında güçlüdür.
Sonuç
Ruby'nin nesne yönelimli yapısı, geliştiricilere güçlü ve esnek araçlar sunar. Sınıflar, nesneler, kapsülleme, kalıtım, polimorfizm ve modüller gibi temel OOP prensipleri, temiz, bakımı kolay ve genişletilebilir kod yazmanın anahtarıdır. Özellikle Ruby'nin mix-in'ler aracılığıyla modül entegrasyonu, diğer dillerdeki çoklu kalıtım sorunlarına zarif bir çözüm sunar. Nesne yönelimli düşünme şeklini benimsemek, Ruby ile daha verimli ve etkili programlar geliştirmenize yardımcı olacaktır. Daha fazla bilgi ve detaylı dokümantasyon için https://ruby-doc.org/ ve diğer güvenilir kaynakları inceleyebilirsiniz.
Nesne Yönelimli Programlamanın Temelleri
OOP, temel olarak dört ana prensip üzerine kuruludur: kapsülleme (encapsulation), kalıtım (inheritance), soyutlama (abstraction) ve polimorfizm (polymorphism). Ruby bu prensipleri kendi özgün ve zarif yoluyla uygular.
Sınıflar ve Nesneler:
Ruby'de programlamanın temel yapı taşı sınıflardır. Bir sınıf, nesnelerin blueprint'i veya şablonu gibidir. Nesneler ise bu sınıflardan türetilen somut varlıklardır. Her nesne, kendi verilerine (örnek değişkenleri) ve davranışlarına (metotlar) sahiptir. Sınıflar `class` anahtar kelimesiyle tanımlanır ve nesneler `.new` metoduyla oluşturulur.
Kod:
class Ogrenci
def initialize(ad, soyad, numara)
@ad = ad
@soyad = soyad
@numara = numara
end
def tam_ad
"#{@ad} #{@soyad}"
end
def ogrenci_bilgisi
"Öğrenci: #{tam_ad}, Numara: #{@numara}"
end
end
# Nesne oluşturma
ogrenci1 = Ogrenci.new("Ali", "Yılmaz", "12345")
ogrenci2 = Ogrenci.new("Ayşe", "Demir", "67890")
puts ogrenci1.ogrenci_bilgisi # => Öğrenci: Ali Yılmaz, Numara: 12345
puts ogrenci2.tam_ad # => Ayşe Demir
Yukarıdaki örnekte `Ogrenci` bir sınıftır ve `ogrenci1`, `ogrenci2` bu sınıftan türetilmiş nesnelerdir. `@ad`, `@soyad`, `@numara` ise bu nesnelerin örnek değişkenleridir.
Kapsülleme (Encapsulation)
Kapsülleme, bir nesnenin iç durumunu dış dünyadan gizleme ve bu duruma kontrollü erişim sağlama prensibidir. Ruby'de bu, örnek değişkenlerine doğrudan erişimi engelleyerek ve onlar üzerinde işlem yapmak için metotlar (getter/setter) sağlayarak gerçekleştirilir. Ruby, bu tür metotları kolayca oluşturmak için `attr_reader`, `attr_writer` ve `attr_accessor` gibi yardımcı metotlar sunar.
Kod:
class Kitap
attr_reader :baslik # Sadece okuma (getter)
attr_writer :sayfa_sayisi # Sadece yazma (setter)
attr_accessor :yazar # Okuma ve yazma (getter/setter)
def initialize(baslik, yazar, sayfa_sayisi)
@baslik = baslik
@yazar = yazar
@sayfa_sayisi = sayfa_sayisi
end
def tanimla
"Kitap: #{@baslik} / Yazar: #{@yazar} / Sayfa Sayısı: #{@sayfa_sayisi}"
end
end
kitap = Kitap.new("Sefiller", "Victor Hugo", 1488)
puts kitap.baslik # => Sefiller
puts kitap.yazar # => Victor Hugo
kitap.yazar = "Honore de Balzac" # Yazar değiştirme
kitap.sayfa_sayisi = 1500 # Sayfa sayısını güncelleme (sadece setter)
puts kitap.tanimla # => Kitap: Sefiller / Yazar: Honore de Balzac / Sayfa Sayısı: 1500
# puts kitap.sayfa_sayisi # Hata verir, çünkü attr_writer sadece yazma içindir, okuma için değil
Kalıtım (Inheritance)
Kalıtım, bir sınıfın (alt sınıf veya türetilmiş sınıf) başka bir sınıfın (üst sınıf veya taban sınıf) özelliklerini ve davranışlarını miras almasına olanak tanır. Bu, kod tekrarını azaltır ve hiyerarşik bir yapı oluşturulmasını sağlar. Ruby'de kalıtım `<` operatörü ile belirtilir.
Kod:
class Hayvan
def initialize(isim)
@isim = isim
end
def konus
"#{@isim} ses çıkarıyor."
end
end
class Kedi < Hayvan
def initialize(isim, cins)
super(isim) # Üst sınıfın initialize metodunu çağırır
@cins = cins
end
def konus
"#{@isim} miyavlıyor. (Cins: #{@cins})"
end
def tirman
"#{@isim} tırmanıyor."
end
end
class Kopek < Hayvan
def konus
"#{@isim} havlıyor."
end
end
kedi = Kedi.new("Tekir", "Ankara Kedisi")
kopek = Kopek.new("Karabaş")
puts kedi.konus # => Tekir miyavlıyor. (Cins: Ankara Kedisi)
puts kopek.konus # => Karabaş havlıyor.
puts kedi.tirman # => Tekir tırmanıyor.
puts kopek.konus # => Karabaş havlıyor.
`super` anahtar kelimesi, alt sınıftan üst sınıfın aynı adlı metodunu çağırmak için kullanılır. Bu, üst sınıf davranışını genişletmek veya geçersiz kılmak için yaygın bir desendir.
Polimorfizm (Polymorphism)
Polimorfizm, farklı sınıflardan nesnelerin aynı mesaja (metot çağrısı) farklı şekillerde yanıt verebilmesi yeteneğidir. Ruby, `duck typing` adı verilen bir polimorfizm biçimini güçlü bir şekilde destekler. Yani, bir nesnenin belirli bir türden olması yerine, belirli bir metodu uygulaması önemlidir. “Eğer ördek gibi yürüyorsa ve ördek gibi vaklıyorsa, o bir ördektir.” prensibi burada devreye girer.
Polimorfizm, aynı arayüzün farklı veri tipleri için farklı davranışlar sergilemesi anlamına gelir. Bu, yazılımın esnekliğini ve genişletilebilirliğini artırır.
Yukarıdaki `Hayvan` örneğinde, hem `Kedi` hem de `Kopek` nesneleri `konus` metoduna farklı şekillerde yanıt vererek polimorfizm sergiler.
Modüller (Modules)
Ruby'de modüller, ortak davranışları sınıflara karıştırmak (mix-in) veya isim alanları (namespaces) oluşturmak için kullanılan yapılardır. Modüllerden nesne oluşturulamaz; sadece sınıflara `include` veya `extend` edilerek kullanılırlar.
`include`: Bir modülü bir sınıfa dahil ettiğinizde, modülün tüm örnek metotları o sınıfın örnek metotları haline gelir. Bu, çoklu kalıtım eksikliğini gidermek için Ruby'nin yoludur.
`extend`: Bir modülü bir sınıfa `extend` ettiğinizde, modülün tüm örnek metotları o sınıfın sınıf metotları haline gelir. Yani, bu metotlar nesneler üzerinde değil, sınıfın kendisi üzerinde çağrılır.
Kod:
module Selamlayici
def selamla
"Merhaba, ben bir #{self.class.name} nesnesiyim!"
end
end
module Loglayici
def log(mesaj)
puts "[LOG] #{Time.now}: #{mesaj}"
end
end
class Kullanici
include Selamlayici # Örnek metot olarak dahil et
extend Loglayici # Sınıf metodu olarak dahil et
def initialize(ad)
@ad = ad
end
def bilgi_ver
"Kullanıcı Adı: #{@ad}"
end
end
kullanici = Kullanici.new("Deniz")
puts kullanici.selamla # => Merhaba, ben bir Kullanici nesnesiyim!
Kullanici.log("Yeni kullanıcı oluşturuldu") # => [LOG] ...: Yeni kullanıcı oluşturuldu
# kullanici.log("...") # Hata verir, çünkü log bir sınıf metodudur
Metot Görünürlüğü (Method Visibility)
Ruby'de metotların görünürlüğünü kontrol etmek için `public`, `protected` ve `private` anahtar kelimeleri kullanılır.
Public: Her yerden erişilebilir. Varsayılan görünürlük modudur.
Protected: Sadece tanımlandığı sınıfın veya alt sınıflarının örnekleri içinde çağrılabilir. `self` üzerinden erişilemez, ancak diğer nesne örnekleri üzerinden erişilebilir.
Private: Sadece tanımlandığı sınıfın içinde, `self` alıcısı olmadan çağrılabilir. Bu, bir nesnenin iç işleyişini dış dünyaya gizlemek için kullanılır.
Kod:
class Hesap
def public_metot
puts "Herkese açık metot"
private_metot # Aynı sınıf içinde çağrılabilir
# self.private_metot # Hata verir, private metot self ile çağrılamaz
end
protected
def protected_metot
puts "Korunan metot"
end
private
def private_metot
puts "Özel metot"
end
end
class AltHesap < Hesap
def test_protected
protected_metot # Alt sınıf içinde çağrılabilir
diger_hesap = Hesap.new
diger_hesap.protected_metot # Başka bir Hesap nesnesinin protected metodunu çağırabilir
end
end
hesap = Hesap.new
hesap.public_metot # => Herkese açık metot
# => Özel metot
alt_hesap = AltHesap.new
alt_hesap.test_protected # => Korunan metot
# => Korunan metot
# hesap.protected_metot # Hata verir, protected dışarıdan çağrılamaz
# hesap.private_metot # Hata verir, private dışarıdan çağrılamaz
`self` Anahtar Kelimesi
Ruby'de `self`, mevcut bağlamdaki nesneyi veya sınıfı temsil eder. Bir örnek metodu içinde `self`, metodu çağıran nesneyi işaret eder. Bir sınıf tanımı içinde (metotlar dışında) veya sınıf metotları içinde `self`, sınıfın kendisini işaret eder. Bu, özellikle dinamik programlama ve meta programlama senaryolarında güçlüdür.
Kod:
class Ornek
def instance_method
puts "Instance metodu içinde self: #{self}"
end
def self.class_method
puts "Class metodu içinde self: #{self}"
end
end
ornek = Ornek.new
ornek.instance_method # => Instance metodu içinde self: #<Ornek:0x...>
Ornek.class_method # => Class metodu içinde self: Ornek
Sonuç
Ruby'nin nesne yönelimli yapısı, geliştiricilere güçlü ve esnek araçlar sunar. Sınıflar, nesneler, kapsülleme, kalıtım, polimorfizm ve modüller gibi temel OOP prensipleri, temiz, bakımı kolay ve genişletilebilir kod yazmanın anahtarıdır. Özellikle Ruby'nin mix-in'ler aracılığıyla modül entegrasyonu, diğer dillerdeki çoklu kalıtım sorunlarına zarif bir çözüm sunar. Nesne yönelimli düşünme şeklini benimsemek, Ruby ile daha verimli ve etkili programlar geliştirmenize yardımcı olacaktır. Daha fazla bilgi ve detaylı dokümantasyon için https://ruby-doc.org/ ve diğer güvenilir kaynakları inceleyebilirsiniz.
Ruby'de OOP'nin Sağladığı Faydalar:
Modülerlik: Kodun mantıksal olarak ayrı parçalara bölünmesi.
Yeniden Kullanılabilirlik: Mevcut sınıfların ve modüllerin farklı projelerde tekrar kullanılması.
Bakım Kolaylığı: Kodun daha anlaşılır ve hatalara karşı dirençli olması.
Genişletilebilirlik: Mevcut kod tabanına yeni özelliklerin kolayca eklenmesi.
Tutarlılık: Veri ve davranışların bir arada tutularak veri bütünlüğünün sağlanması.