Nesne Tabanlı Programlama 2

5 - Kompozisyon ve Polimorfizm

Emre Can Yılmaz

Ondokuz Mayıs Üniversitesi

2025

Giriş

  • Amaç: Nesne Tabanlı Programlama (OOP) prensiplerinden Polimorfizm ve Kompozisyon kavramlarını anlamak.
  • Neden Önemli? Daha esnek, yeniden kullanılabilir ve bakımı kolay kod yazmamızı sağlar.
  • Bugünkü Konular:
    • Kompozisyon (“Has-a” ilişkisi)
    • Polimorfizm ve türleri
    • Duck Typing
    • Pratik örnekler

Kompozisyon Nedir?

  • Tanım: Bir sınıfın, başka sınıflardan nesneleri içermesi.
  • “Has-a” İlişkisi: Bir nesne, başka bir nesneye “sahiptir.”
    • Örnek: “Araba bir motora sahiptir.”
  • Avantajları:
    • Kodun yeniden kullanılabilirliğini artırır.
    • Sınıflar arasında gevşek bağlılık sağlar.
    • Daha modüler bir yapı sunar.

Kompozisyon Örneği 1: Araba ve Motor

class Motor:
    def __init__(self, beygir_gucu):
        self.beygir_gucu = beygir_gucu

    def calistir(self):
        print(f"{self.beygir_gucu} beygirlik motor çalıştı")

class Araba:
    def __init__(self, marka, model, motor_gucu):
        self.marka = marka
        self.model = model
        self.motor = Motor(motor_gucu)  # Kompozisyon

    def sur(self):
        print(f"{self.marka} {self.model} hareket ediyor")
        self.motor.calistir()

Kullanım

araba = Araba("Toyota", "Corolla", 120)
araba.sur()
# Çıktı:
# Toyota Corolla hareket ediyor
# 120 beygirlik motor çalıştı

Kompozisyon Örneği 2: Bilgisayar Sistemi

class CPU:
    def process(self):
        print("Veri işleniyor")

class RAM:
    def load(self):
        print("Veri belleğe yükleniyor")

class Storage:
    def read(self):
        print("Veri depodan okunuyor")
class Computer:
    def __init__(self):
        self.cpu = CPU()      # Kompozisyon
        self.ram = RAM()      # Kompozisyon
        self.storage = Storage()  # Kompozisyon

    def run(self):
        self.storage.read()
        self.ram.load()
        self.cpu.process()

# Kullanım
bilgisayar = Computer()
bilgisayar.run()
# Çıktı:
# Veri depodan okunuyor
# Veri belleğe yükleniyor
# Veri işleniyor

Kompozisyon Örneği 3: Üniversite Sistemi

class Ogrenci:
    def __init__(self, ad, numara):
        self.ad = ad
        self.numara = numara

class Ders:
    def __init__(self, ad, kod):
        self.ad = ad
        self.kod = kod
        self.ogrenciler = []

    def ogrenci_ekle(self, ogrenci):
        self.ogrenciler.append(ogrenci)

class Universite:
    def __init__(self, ad):
        self.ad = ad
        self.dersler = []  # Kompozisyon

    def ders_ekle(self, ders):
        self.dersler.append(ders)
# Kullanım
uni = Universite("Marmara Üniversitesi")
ntp = Ders("Nesne Tabanlı Programlama", "BLM2012")
uni.ders_ekle(ntp)
ahmet = Ogrenci("Ahmet Yılmaz", "2023001")
ntp.ogrenci_ekle(ahmet)

Kompozisyon Örneği 4: Öğrenci ve Adres

class Adres:
    def __init__(self, sokak, sehir, posta_kodu):
        self.sokak = sokak
        self.sehir = sehir
        self.posta_kodu = posta_kodu

    def adres_bilgisi(self):
        return f"{self.sokak}, {self.sehir}, {self.posta_kodu}"

class Ogrenci:
    def __init__(self, ad, soyad, sokak, sehir, posta_kodu):
        self.ad = ad
        self.soyad = soyad
        self.adres = Adres(sokak, sehir, posta_kodu)  # Kompozisyon

    def ogrenci_bilgisi(self):
        return f"{self.ad} {self.soyad}\nAdres: {self.adres.adres_bilgisi()}"
# Kullanım
ogrenci = Ogrenci("Ali", "Veli", "Atatürk Cad.", "İstanbul", "34000")
print(ogrenci.ogrenci_bilgisi())
# Çıktı:
# Ali Veli
# Adres: Atatürk Cad., İstanbul, 34000

Polimorfizm (Çok Biçimlilik) Nedir?

Tanım: Farklı sınıflardan nesnelerin aynı arayüzü kullanarak farklı davranışlar sergilemesi.

Faydaları:

  • Kodun esnekliğini artırır.
  • Genişletilebilirlik sağlar.
  • Kod tekrarını azaltır.

Python’da: Dinamik tip sistemiyle doğal olarak desteklenir.

Polimorfizm Örneği 1: Hayvan Sesleri

class Hayvan:
    def ses_cikar(self):
        pass

class Kedi(Hayvan):
    def ses_cikar(self):
        return "Miyav!"

class Kopek(Hayvan):
    def ses_cikar(self):
        return "Hav hav!"

class Kus(Hayvan):
    def ses_cikar(self):
        return "Cik cik!"
# Kullanım
hayvanlar = [Kedi(), Kopek(), Kus()]
for hayvan in hayvanlar:
    print(hayvan.ses_cikar())
# Çıktı:
# Miyav!
# Hav hav!
# Cik cik!

Polimorfizm Örneği 2: Şekiller

class Sekil:
    def alan(self):
        pass

class Daire(Sekil):
    def __init__(self, yaricap):
        self.yaricap = yaricap

    def alan(self):
        return 3.14 * self.yaricap ** 2

class Dikdortgen(Sekil):
    def __init__(self, genislik, yukseklik):
        self.genislik = genislik
        self.yukseklik = yukseklik

    def alan(self):
        return self.genislik * self.yukseklik
# Kullanım
sekiller = [Daire(5), Dikdortgen(4, 6)]
for sekil in sekiller:
    print(sekil.alan())
# Çıktı:
# 78.5
# 24

Polimorfizm Örneği 3: Banka Hesapları

class Hesap:
    def __init__(self, bakiye=0):
        self.bakiye = bakiye

    def para_cek(self, miktar):
        if miktar <= self.bakiye:
            self.bakiye -= miktar
            return f"{miktar} TL çekildi. Yeni bakiye: {self.bakiye}"
        return "Yetersiz bakiye"

class VadesizHesap(Hesap):
    def para_cek(self, miktar):
        limit = self.bakiye + 1000  # Ek limit
        if miktar <= limit:
            self.bakiye -= miktar
            return f"{miktar} TL çekildi. Yeni bakiye: {self.bakiye}"
        return "Limit aşımı"
# Kullanım
hesaplar = [Hesap(500), VadesizHesap(500)]
for hesap in hesaplar:
    print(hesap.para_cek(600))
# Çıktı:
# Yetersiz bakiye
# 600 TL çekildi. Yeni bakiye: -100

Duck Typing Nedir?

Tanım: “Eğer ördek gibi yürüyor ve vaklıyorsa, o bir ördektir.”

Özellik: Nesnenin türü değil, davranışları önemlidir.

Python’da: Kalıtım olmadan, aynı metot isimleriyle polimorfizm sağlanır.

Duck Typing Örneği 1: Ördek ve Robot

class Ordek:
    def yuz(self):
        print("Ördek yüzüyor")

    def vakla(self):
        print("Vak vak!")

class Robot:
    def yuz(self):
        print("Robot yüzüyor")

    def vakla(self):
        print("Robot vaklıyor")

def ordek_eylemleri(nesne):
    nesne.yuz()
    nesne.vakla()
# Kullanım
ordek = Ordek()
robot = Robot()
ordek_eylemleri(ordek)
ordek_eylemleri(robot)
# Çıktı:
# Ördek yüzüyor
# Vak vak!
# Robot yüzüyor
# Robot vaklıyor

Duck Typing Örneği 2: Dosya Benzeri Nesneler

class StringIO:
    def __init__(self, icerik=""):
        self.icerik = icerik

    def read(self):
        return self.icerik

class GercekDosya:
    def read(self):
        return "Dosya içeriği"

def oku(nesne):
    print(nesne.read())
# Kullanım
string_io = StringIO("Merhaba")
dosya = GercekDosya()
oku(string_io)  # Merhaba
oku(dosya)      # Dosya içeriği

Kompozisyon ve Polimorfizm Birlikte: Akıllı Ev

class CihazArayuz:
    def ac(self):
        pass

    def kapat(self):
        pass

class Televizyon(CihazArayuz):
    def ac(self):
        return "TV açıldı"

    def kapat(self):
        return "TV kapandı"

class MuzikCalar(CihazArayuz):
    def ac(self):
        return "Müzik çalar açıldı"

    def kapat(self):
        return "Müzik çalar kapandı"
class AkilliEv:
    def __init__(self):
        self.cihazlar = []  # Kompozisyon

    def cihaz_ekle(self, cihaz):
        self.cihazlar.append(cihaz)

    def tumunu_ac(self):
        for cihaz in self.cihazlar:
            print(cihaz.ac())  # Polimorfizm

# Kullanım
ev = AkilliEv()
ev.cihaz_ekle(Televizyon())
ev.cihaz_ekle(MuzikCalar())
ev.tumunu_ac()
# Çıktı:
# TV açıldı
# Müzik çalar açıldı

Özet

  • Kompozisyon: “Has-a” ilişkisiyle nesneleri birleştirir, esneklik sağlar.

  • Polimorfizm: Farklı nesnelerin aynı arayüzle farklı davranışlar sergilemesini sağlar.

  • Duck Typing: Nesnelerin davranışlarına odaklanır, kalıtım zorunlu değildir.

  • Birlikte Kullanım: Daha güçlü ve modüler sistemler tasarlanır.

Alıştırmalar

Soru 1: Kompozisyon - Kitap ve Yazar

  • Bir Kitap sınıfı ve bir Yazar sınıfı tasarlayın. Her kitap, bir veya daha fazla yazara sahip olabilir.
  • Kitap sınıfı, yazar nesnelerini içermeli (kompozisyon).
  • Kitap sınıfında, kitabın adını ve yazarlarını listeleyen bir metot olsun.
  • Yazar sınıfında ise yazarın adı ve soyadı olsun.

Talimatlar:

  • Yazar sınıfı, ad ve soyad özniteliklerine sahip olmalı.
  • Kitap sınıfı, kitap_adi ve yazarlar (yazar nesnelerinden oluşan bir liste) özniteliklerine sahip olmalı.
  • Kitap sınıfında, kitabın adını ve yazarlarını listeleyen bir metot (bilgi_ver gibi) tanımlayın.

Beklenen Çıktı Örneği:

kitap = Kitap("Python 101", [Yazar("Ali", "Yılmaz"), Yazar("Ayşe", "Kaya")])
kitap.bilgi_ver()
# Çıktı:
# Kitap: Python 101
# Yazarlar: Ali Yılmaz, Ayşe Kaya

Soru 2: Polimorfizm - Taşıtlar

  • Taşıt adında bir temel sınıf ve bu sınıftan türeyen Araba, Bisiklet ve Uçak sınıfları tasarlayın.
  • Her taşıtın hareket_et adında bir metodu olsun ve bu metot her sınıfta farklı bir çıktı versin (örneğin, “Araba yolda gidiyor”, “Bisiklet pedal çevriliyor”, “Uçak havada uçuyor”).
  • Ardından, bir taşıt listesi oluşturun ve listedeki her taşıtın hareket_et metodunu çağırın.

Talimatlar:

  • Taşıt sınıfında hareket_et metodunu tanımlayın (geçici olarak pass kullanabilirsiniz).
  • Araba, Bisiklet ve Uçak sınıflarında hareket_et metodunu override edin.
  • Bir liste oluşturun ve bu listeye farklı taşıt nesneleri ekleyin.
  • Listedeki her taşıtın hareket_et metodunu çağırarak polimorfizmi gösterin.

Beklenen Çıktı Örneği:

tasitlar = [Araba(), Bisiklet(), Ucak()]
for tasit in tasitlar:
    print(tasit.hareket_et())
# Çıktı:
# Araba yolda gidiyor
# Bisiklet pedal çevriliyor
# Uçak havada uçuyor

Soru 3: Duck Typing - Yazıcı ve Fotokopi Makinesi

  • Yazıcı ve FotokopiMakinesi adında iki sınıf tasarlayın.
  • Her iki sınıf da yazdir adında bir metot içersin, ancak bu metotlar farklı çıktılar versin (örneğin, “Yazıcı belgeyi yazdırıyor”, “Fotokopi makinesi belgeyi kopyalıyor”).
  • Ardından, bir fonksiyon yazın ki bu fonksiyon bir nesne alsın ve o nesnenin yazdir metodunu çağırsın.
  • Bu fonksiyonu hem Yazıcı hem de FotokopiMakinesi nesneleriyle test edin.

Talimatlar:

  • Yazıcı ve FotokopiMakinesi sınıflarında yazdir metodunu tanımlayın.
  • yazdir_fonksiyonu adında bir fonksiyon yazın ki bu fonksiyon bir nesne parametresi alsın ve o nesnenin yazdir metodunu çağırsın.
  • Hem Yazıcı hem de FotokopiMakinesi nesneleri oluşturun ve bu fonksiyonu her ikisiyle de çağırarak duck typing’i gösterin.

Beklenen Çıktı Örneği:

def yazdir_fonksiyonu(nesne):
    print(nesne.yazdir())

yazici = Yazici()
fotokopi = FotokopiMakinesi()
yazdir_fonksiyonu(yazici)
yazdir_fonksiyonu(fotokopi)
# Çıktı:
# Yazıcı belgeyi yazdırıyor
# Fotokopi makinesi belgeyi kopyalıyor

Soru 4: Kompozisyon ve Polimorfizm - Oyun ve Karakterler

  • Bir Oyun sınıfı tasarlayın. Bu sınıf, farklı Karakter nesnelerini içersin (kompozisyon).
  • Karakter adında bir temel sınıf ve bu sınıftan türeyen Savaşçı, Büyücü ve Okçu sınıfları olsun.
  • Her karakterin saldir adında bir metodu olsun ve bu metot her sınıfta farklı bir saldırı tipi gerçekleştirsin (örneğin, “Savaşçı kılıçla saldırıyor”, “Büyücü ateş topu atıyor”, “Okçu ok atıyor”).
  • Oyun sınıfında, tüm karakterlerin saldırmasını sağlayan bir metot olsun.

Talimatlar:

  • Karakter sınıfında saldir metodunu tanımlayın (geçici olarak pass kullanabilirsiniz).
  • Savaşçı, Büyücü ve Okçu sınıflarında saldir metodunu override edin.
  • Oyun sınıfında, karakterler adında bir liste özniteliği olsun (kompozisyon).
  • Oyun sınıfında, tüm karakterlerin saldir metodunu çağıran bir metot (tum_karakterler_saldir gibi) tanımlayın.
  • Bir Oyun nesnesi oluşturun, farklı karakterler ekleyin ve tum_karakterler_saldir metodunu çağırarak hem kompozisyonu hem de polimorfizmi gösterin.

Beklenen Çıktı Örneği:

oyun = Oyun()
oyun.karakterler.extend([Savasci(), Buyucu(), Okcu()])
oyun.tum_karakterler_saldir()
# Çıktı:
# Savaşçı kılıçla saldırıyor
# Büyücü ateş topu atıyor
# Okçu ok atıyor