Neler yeni

Yazılım Forum

Tüm özelliklerimize erişmek için şimdi bize katılın. Kayıt olduktan ve giriş yaptıktan sonra konu oluşturabilecek, mevcut konulara yanıt gönderebilecek, itibar kazanabilecek, özel mesajlaşmaya erişebilecek ve çok daha fazlasını yapabileceksiniz! Bu hizmetlerimiz ise tamamen ücretsiz ve kurallara uyulduğu sürece sınırsızdır, o zaman ne bekliyorsunuz? Hadi, sizde aramıza katılın!

Ruby ile Nesne Yönelimli Tasarım: Temellerden İleri Seviyelere Kapsamlı Rehber

Ruby ile Nesne Yönelimli Tasarım: Temellerden İleri Seviyelere

Günümüz yazılım mühendisliğinde, Nesne Yönelimli Programlama (NYP) veya İngilizce adıyla Object-Oriented Programming (OOP), en yaygın ve güçlü paradigmalarından biridir. Ruby, bu paradigmanın saf bir temsilcisidir; her şeyin bir nesne olarak kabul edildiği bir yapı sunar. Bu felsefe, Ruby'yi OOP prensiplerini uygulamak ve karmaşık sistemler geliştirmek için eşsiz bir dil haline getirir. Bu kapsamlı yazıda, Ruby'nin nesne yönelimli doğasını derinlemesine keşfedecek, temel kavramlardan ileri konulara kadar geniş bir yelpazeyi ele alacağız. Sınıflar ve nesnelerden başlayarak, miras (inheritance), polimorfizm (polymorphism), kapsülleme (encapsulation) ve modüller (mixins) gibi kilit prensipleri detaylandıracağız. Ayrıca, sağlam ve sürdürülebilir yazılım tasarımı için önemli olan bazı temel tasarım prensiplerine ve en iyi uygulamalara da değineceğiz.

1. Sınıflar ve Nesneler: OOP'nin Yapı Taşları

Ruby'de her değer bir nesnedir ve bu nesneler sınıfların örnekleridir. Sınıflar, belirli bir türdeki nesnelerin özelliklerini (durum, instance değişkenleri) ve davranışlarını (metotlar) tanımlayan şablonlardır. Bir sınıf, nesneleri nasıl oluşturacağımızı ve bu nesnelerin nasıl etkileşime gireceğini belirler.

Kod:
class Film
  # initialize metodu, bir Film nesnesi oluşturulduğunda otomatik olarak çağrılır.
  # Bu, nesnenin ilk durumunu (instance değişkenleri) ayarlamak için kullanılır.
  def initialize(baslik, yonetmen, yayin_yili)
    @baslik = baslik           # @ işareti instance değişkenlerini belirtir
    @yonetmen = yonetmen
    @yayin_yili = yayin_yili
    @izlendi = false           # Varsayılan olarak izlenmedi
  end

  # Film bilgilerini gösteren bir metot
  def bilgileri_goster
    "Başlık: #{@baslik}, Yönetmen: #{@yonetmen}, Yayın Yılı: #{@yayin_yili}"
  end

  # Filmi izlendi olarak işaretleyen metot
  def izle!
    @izlendi = true
    "Film izlendi: #{@baslik}"
  end

  # Filmin izlenip izlenmediğini kontrol eden metot (boolean döndürür)
  def izlendi?
    @izlendi
  end
end

# Film sınıfından yeni nesneler (objeler) oluşturma
film1 = Film.new("Esaretin Bedeli", "Frank Darabont", 1994)
film2 = Film.new("Yüzüklerin Efendisi: Yüzük Kardeşliği", "Peter Jackson", 2001)

# Nesnelerin metotlarını çağırma
puts film1.bilgileri_goster
# Çıktı: Başlık: Esaretin Bedeli, Yönetmen: Frank Darabont, Yayın Yılı: 1994

puts film2.bilgileri_goster
# Çıktı: Başlık: Yüzüklerin Efendisi: Yüzük Kardeşliği, Yönetmen: Peter Jackson, Yayın Yılı: 2001

puts film1.izle!
# Çıktı: Film izlendi: Esaretin Bedeli

puts film1.izlendi?
# Çıktı: true

puts film2.izlendi?
# Çıktı: false
Yukarıdaki örnekte `Film` bir sınıftır, `film1` ve `film2` ise bu sınıfın farklı örnekleridir (nesneleridir). Her nesne kendi `@baslik`, `@yonetmen`, `@yayin_yili` ve `@izlendi` değerlerine sahiptir.

2. Miras (Inheritance): Kod Tekrarını Azaltma

Miras, 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 temel sınıf) özelliklerini ve davranışlarını devralmasına olanak tanıyan bir OOP prensibidir. Bu, kodun yeniden kullanılabilirliğini artırır, hiyerarşik ilişkiler kurmayı sağlar ve genel yazılım mimarisini daha düzenli hale getirir. Ruby'de miras, `<` operatörü ile belirtilir.

Kod:
class Arac
  def initialize(tekerlek_sayisi, renk)
    @tekerlek_sayisi = tekerlek_sayisi
    @renk = renk
  end

  def sur
    "Araç hareket ediyor."
  end

  def bilgileri_goster
    "Tekerlek Sayısı: #{@tekerlek_sayisi}, Renk: #{@renk}"
  end
end

class Otomobil < Arac # Otomobil sınıfı Arac sınıfından miras alır
  def initialize(marka, model, renk, tekerlek_sayisi = 4)
    super(tekerlek_sayisi, renk) # Üst sınıfın initialize metodunu çağırır
    @marka = marka
    @model = model
  end

  # Üst sınıftaki 'sur' metodunu geçersiz kılma (method overriding)
  def sur
    "Otomobil asfalt üzerinde güvenle sürülüyor!"
  end

  def tam_bilgileri_goster
    "Marka: #{@marka}, Model: #{@model}, #{super}" # super ile üst sınıfın metodunu çağırabiliriz
  end
end

class Bisiklet < Arac # Bisiklet sınıfı da Arac sınıfından miras alır
  def initialize(tip, renk, tekerlek_sayisi = 2)
    super(tekerlek_sayisi, renk)
    @tip = tip
  end

  def sur
    "Bisiklet pedallanarak ilerliyor!"
  end

  def tam_bilgileri_goster
    "Tip: #{@tip}, #{super}"
  end
end

otomobil1 = Otomobil.new("Honda", "Civic", "Siyah")
puts otomobil1.sur               # Çıktı: Otomobil asfalt üzerinde güvenle sürülüyor!
puts otomobil1.tam_bilgileri_goster
# Çıktı: Marka: Honda, Model: Civic, Tekerlek Sayısı: 4, Renk: Siyah

bisiklet1 = Bisiklet.new("Dağ Bisikleti", "Mavi")
puts bisiklet1.sur               # Çıktı: Bisiklet pedallanarak ilerliyor!
puts bisiklet1.tam_bilgileri_goster
# Çıktı: Tip: Dağ Bisikleti, Tekerlek Sayısı: 2, Renk: Mavi
`super` anahtar kelimesi, alt sınıfın üst sınıfın metotlarını çağırmasına olanak tanır. Bu, özellikle constructor (`initialize`) metotlarında ve metot geçersiz kılma durumlarında çok kullanışlıdır.

3. Polimorfizm (Polymorphism): Çok Biçimlilik

Polimorfizm, "çok biçimlilik" anlamına gelir ve farklı sınıflardaki nesnelerin aynı metot çağrısına farklı şekillerde yanıt vermesini sağlayan bir OOP prensibidir. Ruby'de bu, özellikle Duck Typing felsefesiyle doğal olarak desteklenir: "Eğer bir ördek gibi yürüyorsa ve bir ördek gibi vakvaklıyorsa, o bir ördektir." Yani, bir nesnenin sınıf türü yerine, sahip olduğu metotlar ve bu metotların davranışları önemlidir.

Kod:
class Kedi
  def ses_cikar
    "Miyav!"
  end
end

class Kopek
  def ses_cikar
    "Hav hav!"
  end
end

class Ordek
  def ses_cikar
    "Vak vak!"
  end
end

class Insan
  def ses_cikar
    "Merhaba!"
  end
end

hayvanlar = [Kedi.new, Kopek.new, Ordek.new, Insan.new]

puts "Hayvanların çıkardığı sesler:"
hayvanlar.each do |canli|
  puts canli.ses_cikar # Her nesne kendi 'ses_cikar' metodunu çağırır
end
# Çıktı:
# Miyav!
# Hav hav!
# Vak vak!
# Merhaba!
Yukarıdaki örnekte, her ne kadar farklı sınıflardan olsalar da, `hayvanlar` dizisindeki her nesne `ses_cikar` metoduna sahip olduğu için, onları aynı şekilde işleyebiliriz. Bu, esnek ve genişletilebilir kod yazmayı mümkün kılar.

4. Kapsülleme (Encapsulation): Veri Gizliliği

Kapsülleme, nesnenin iç durumunun (instance değişkenleri) dış dünyadan gizlenmesi ve bu duruma yalnızca nesnenin kendi metotları aracılığıyla erişilmesidir. Bu prensip, nesnenin iç işleyişini dış müdahalelerden korur ve kodun daha güvenli ve bakımı kolay olmasını sağlar. Ruby'de kapsülleme, metotların public, protected ve private olarak tanımlanmasıyla sağlanır.
  • Public Metotlar: Sınıfın dışından erişilebilirler ve sınıfın arayüzünü oluştururlar. Ruby'de varsayılan olarak tüm metotlar public'tir.
  • Protected Metotlar: Sadece sınıf içinden ve o sınıfın alt sınıflarından erişilebilirler. Aynı türdeki başka bir nesneye de erişebilirler.
  • Private Metotlar: Sadece tanımlandıkları sınıfın içinden çağrılabilirler ve bir alıcı (receiver) olmadan çağrılmalıdırlar (yani `self.metot_adi` şeklinde değil, sadece `metot_adi` şeklinde).
Ruby'de `attr_reader`, `attr_writer` ve `attr_accessor` gibi yardımcı metotlar, instance değişkenlerine erişimi (getter/setter metotları) otomatik olarak oluşturarak kapsüllemeyi kolaylaştırır.

Kod:
class BankaHesabi
  attr_reader :hesap_numarasi # Sadece okunabilir (getter)
  attr_accessor :hesap_sahibi # Hem okunabilir hem yazılabilir (getter ve setter)

  def initialize(hesap_numarasi, hesap_sahibi, bakiye)
    @hesap_numarasi = hesap_numarasi
    @hesap_sahibi = hesap_sahibi
    @bakiye = bakiye # Bakiye sadece metotlar aracılığıyla değiştirilebilir
  end

  def bakiye_sorgula # Public metot
    "#{hesap_sahibi}'nin mevcut bakiyesi: #{@bakiye} TL"
  end

  def para_yatir(miktar) # Public metot
    if miktar > 0
      @bakiye += miktar
      puts "#{miktar} TL yatırıldı. Yeni bakiye: #{@bakiye} TL"
    else
      puts "Yatırılacak miktar pozitif olmalı."
    end
  end

  def para_cek(miktar) # Public metot
    if yeterli_bakiye?(miktar) # Private metodu çağırıyoruz
      @bakiye -= miktar
      puts "#{miktar} TL çekildi. Yeni bakiye: #{@bakiye} TL"
    else
      puts "Yetersiz bakiye veya geçersiz miktar!"
    end
  end

  private # Bu noktadan sonraki metotlar private'tır

  # Bu metot sadece BankaHesabi sınıfı içinde çağrılabilir.
  def yeterli_bakiye?(miktar)
    miktar > 0 && miktar <= @bakiye
  end
end

hesap = BankaHesabi.new("123456789", "Can Yılmaz", 5000)

puts hesap.bakiye_sorgula
# Çıktı: Can Yılmaz'ın mevcut bakiyesi: 5000 TL

hesap.para_yatir(1500)
# Çıktı: 1500 TL yatırıldı. Yeni bakiye: 6500 TL

hesap.para_cek(2000)
# Çıktı: 2000 TL çekildi. Yeni bakiye: 4500 TL

hesap.para_cek(5000)
# Çıktı: Yetersiz bakiye veya geçersiz miktar!

puts hesap.hesap_numarasi # attr_reader sayesinde erişilebilir
# Çıktı: 123456789

hesap.hesap_sahibi = "Can Yılmazer" # attr_accessor sayesinde değiştirilebilir
puts hesap.hesap_sahibi
# Çıktı: Can Yılmazer

# hesap.yeterli_bakiye?(100) # Bu satır bir hata (NoMethodError) verir çünkü private metot dışarıdan çağrılamaz.
Kapsülleme, nesnenin sadece dış dünyayla paylaşmak istediği bilgiyi sunarak, iç karmaşıklığı gizler ve dış kodun nesnenin iç durumunu yanlışlıkla bozmasını engeller.

5. Modüller ve Karışımlar (Modules & Mixins): Davranış Paylaşımı

Ruby'de çoklu miras doğrudan desteklenmez, ancak bu eksikliği modüller giderir. Modüller, metotları, sabitleri ve diğer modülleri bir araya getiren kapsayıcılardır. Sınıflara karıştırılabilir (mix-in) özelliğini sunarlar, böylece bir sınıf birden fazla modülün davranışlarını devralabilir. Bu, kodun yeniden kullanılabilirliğini artırmanın ve sınıflar arasında ortak davranışları paylaşmanın çok esnek bir yoludur.

Modül Kullanımının Avantajları:
  • Kodun yeniden kullanılabilirliğini maksimize eder.
  • Sınıflar arasında davranışları (metotlar) paylaşmak için hiyerarşik mirasın sınırlamalarına takılmadan esnek bir yol sunar.
  • Tek sorumluluk prensibini (Single Responsibility Principle) destekleyerek, sınıfların daha odaklanmış olmasını sağlar.
  • Çoklu mirasın getirebileceği karmaşıklığı ve "ölü eşkenar dörtgen" sorununu önler.

Kod:
# Uçma yeteneğini temsil eden bir modül
module Ucababilir
  def uc
    "#{self.class} uçuyor!" # self.class, çağrılan nesnenin sınıfını verir
  end
end

# Yüzme yeteneğini temsil eden bir modül
module Yuzebilir
  def yuz
    "#{self.class} yüzüyor!"
  end
end

# Ses çıkarma yeteneğini temsil eden bir modül
module SesCikarma
  def ses_cikar(ses)
    "#{self.class} #{ses} diyor!"
  end
end

class Kus
  include Ucababilir # Kus, Ucababilir modülünü içerir (mixin)
  include SesCikarma

  def initialize(ad)
    @ad = ad
  end

  def bilgileri_goster
    "Adı: #{@ad}, Tür: Kus"
  end
end

class Ordek
  include Ucababilir # Ordek hem uçabilir...
  include Yuzebilir  # ...hem de yüzebilir
  include SesCikarma

  def initialize(ad)
    @ad = ad
  end

  def bilgileri_goster
    "Adı: #{@ad}, Tür: Ordek"
  end
end

class Gemi
  include Yuzebilir # Gemi sadece yüzebilir
end

kus = Kus.new("Serçe")
puts kus.bilgileri_goster # Adı: Serçe, Tür: Kus
puts kus.uc               # Kus uçuyor!
puts kus.ses_cikar("cik cik") # Kus cik cik diyor!

ordek = Ordek.new("Donald")
puts ordek.bilgileri_goster # Adı: Donald, Tür: Ordek
puts ordek.uc               # Ordek uçuyor!
puts ordek.yuz              # Ordek yüzüyor!
puts ordek.ses_cikar("vak vak") # Ordek vak vak diyor!

gemi = Gemi.new
puts gemi.yuz               # Gemi yüzüyor!
# puts gemi.uc              # Hata verir: undefined method `uc' for #<Gemi:...>
`include` anahtar kelimesi, bir modüldeki metotları bir sınıfın instance metotları olarak ekler. Böylece o sınıfın nesneleri, modülün sağladığı metotları kullanabilir. Modüller, davranışları küçük, yönetilebilir parçalara ayırarak kod tabanının modülerliğini ve anlaşılırlığını artırır.

6. Nesne Yönelimli Tasarım Prensipleri ve En İyi Uygulamalar

Nesne yönelimli programlamanın sadece sınıfları ve nesneleri kullanmaktan ibaret olmadığını anlamak önemlidir. Sağlam, esnek ve bakımı kolay kod yazmak için belirli tasarım prensiplerine uymak büyük önem taşır. Bu prensipler, yazılımın gelecekteki değişikliklere daha iyi uyum sağlamasına ve daha az hata içermesine yardımcı olur. En bilinen ve uygulanan prensiplerden biri SOLID prensipleridir:

  • Single Responsibility Principle (Tek Sorumluluk Prensibi): Bir sınıfın veya modülün yalnızca bir nedeni olmalıdır değişmek için. Yani, yalnızca bir işlevi olmalı ve o işlevi tam olarak yerine getirmelidir.
  • Open/Closed Principle (Açık/Kapalı Prensibi): Yazılım varlıkları (sınıflar, modüller, fonksiyonlar vb.) geliştirmeye açık, ancak değiştirmeye kapalı olmalıdır. Yeni işlevsellik eklerken mevcut kodu değiştirmek yerine, onu genişletmelisiniz.
  • Liskov Substitution Principle (Liskov Yerine Geçme Prensibi): Bir temel sınıfın (üst sınıf) nesneleri, türetilmiş sınıfların (alt sınıflar) nesneleriyle değiştirilebilir olmalıdır; bu, istemci kodunu bozmamalıdır.
  • Interface Segregation Principle (Arayüz Ayırma Prensibi): İstemciler, kullanmadıkları arayüzlere bağımlı olmaya zorlanmamalıdır. Büyük, genel arayüzler yerine küçük, özel arayüzler tercih edilmelidir. Ruby'de bu, modüllerin iyi tasarlanmasıyla sağlanır.
  • Dependency Inversion Principle (Bağımlılık Ters Çevirme Prensibi): Yüksek seviyeli modüller, düşük seviyeli modüllere bağlı olmamalıdır; her ikisi de soyutlamalara bağlı olmalıdır. Soyutlamalar detaylara bağlı olmamalı, detaylar soyutlamalara bağlı olmalıdır.

Bu prensipler, yazılımın modülerliğini, esnekliğini ve sürdürülebilirliğini artırır. Ruby'nin esnekliği ve dinamik yapısı, bu prensipleri uygulamak için bolca fırsat sunar.
Ayrıca, genel yazılım mühendisliğinde geçerli olan bazı evrensel en iyi uygulamalar da vardır:
  • DRY (Don't Repeat Yourself - Kendini Tekrar Etme): Kod tekrarından kaçının. Ortak işlevleri metotlara veya modüllere taşıyın.
  • YAGNI (You Ain't Gonna Need It - İhtiyacın Olmayacak): Gelecekte ihtiyaç duyulabilecek özellikler için erkenden kod yazmaktan kaçının. Sadece mevcut ihtiyaçları karşılayacak kadar kod yazın.
  • KISS (Keep It Simple, Stupid - Basit Tut, Aptal): Kodunuzu olabildiğince basit ve anlaşılır tutmaya çalışın. Gereksiz karmaşıklıktan kaçının.

"Ruby, programcılara 'mutlu' olmak için tasarlanmış bir dildir." - Yukihiro "Matz" Matsumoto (Ruby'nin yaratıcısı)
Bu alıntı, Ruby'nin tasarım felsefesini özetler niteliktedir. Dilin esnekliği ve nesne yönelimli yapısı, geliştiricilerin sadece işlevsel değil, aynı zamanda zarif ve okunabilir kodlar yazmasını teşvik eder.

Sonuç

Ruby'nin nesne yönelimli programlama yetenekleri, onu karmaşık ve büyük ölçekli uygulamalar geliştirmek için güçlü ve çok yönlü bir dil haline getirir. Sınıflar, nesneler, miras, polimorfizm, kapsülleme ve modüller gibi temel kavramları derinlemesine anlamak, Ruby ile daha temiz, daha verimli ve daha sürdürülebilir yazılımlar yazmanızın temelini oluşturur. Bu prensipleri kodunuzda bilinçli bir şekilde uygulamak, uzun vadede projenizin başarısı için kritik öneme sahiptir.

Yazılım geliştirme sürekli bir öğrenme sürecidir. Nesne yönelimli tasarım prensiplerini ve Ruby'nin sunduğu araçları daha fazla keşfetmek için pratik yapmaya ve örnekler üzerinde çalışmaya devam edin.
Daha fazla kaynak için, Ruby'nin resmi dokümantasyonunu ziyaret edebilirsiniz: https://www.ruby-lang.org/tr/documentation/. Nesne Yönelimli Programlama hakkında genel bilgi ve tarihi gelişim için ise Wikipedia sayfasını inceleyebilirsiniz: https://tr.wikipedia.org/wiki/Nesne_yönelimli_programlama.

Unutmayın, iyi nesne yönelimli tasarım, sadece kodu daha düzenli hale getirmekle kalmaz, aynı zamanda takım çalışmasını kolaylaştırır ve yazılımın ömrünü uzatır.
 
shape1
shape2
shape3
shape4
shape5
shape6
Üst

Bu web sitenin performansı Hazal Host tarafından sağlanmaktadır.

YazilimForum.com.tr internet sitesi, 5651 sayılı Kanun’un 2. maddesinin 1. fıkrasının (m) bendi ve aynı Kanun’un 5. maddesi kapsamında Yer Sağlayıcı konumundadır. Sitede yer alan içerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır.

YazilimForum.com.tr, kullanıcılar tarafından paylaşılan içeriklerin doğruluğunu, güncelliğini veya hukuka uygunluğunu garanti etmez ve içeriklerin kontrolü veya araştırılması ile yükümlü değildir. Kullanıcılar, paylaştıkları içeriklerden tamamen kendileri sorumludur.

Hukuka aykırı içerikleri fark ettiğinizde lütfen bize bildirin: lydexcoding@gmail.com

Sitemiz, kullanıcıların paylaştığı içerik ve bilgileri 6698 sayılı KVKK kapsamında işlemektedir. Kullanıcılar, kişisel verileriyle ilgili haklarını KVKK Politikası sayfasından inceleyebilir.

Sitede yer alan reklamlar veya üçüncü taraf bağlantılar için YazilimForum.com.tr herhangi bir sorumluluk kabul etmez.

Sitemizi kullanarak Forum Kuralları’nı kabul etmiş sayılırsınız.

DMCA.com Protection Status Copyrighted.com Registered & Protected