Menu
Coddy logo textTech

Interface'ler ile Polimorfizm

Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 41 / 107.

Polimorfizm, farklı türlerin ortak bir arayüz aracılığıyla tek tip olarak ele alınmasına olanak tanır. Go'da bu, kalıtım veya sınıf hiyerarşileri olmadan tamamen arayüzler aracılığıyla gerçekleştirilir.

Bir fonksiyon parametre olarak bir arayüz (interface) türü kabul ettiğinde, bu arayüzü uygulayan herhangi bir somut tür içeri aktarılabilir. Fonksiyonun belirli türü bilmesine gerek yoktur; yalnızca arayüz tarafından tanımlanan davranışla ilgilenir:

type Speaker interface {
    Speak() string
}

type Dog struct{ Name string }
func (d Dog) Speak() string { return "Woof!" }

type Cat struct{ Name string }
func (c Cat) Speak() string { return "Meow!" }

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

Artık MakeSound, bir Speak() metoduna sahip olan her türle çalışır:

func main() {
    dog := Dog{Name: "Rex"}
    cat := Cat{Name: "Whiskers"}
    
    MakeSound(dog)  // Hav!
    MakeSound(cat)  // Miyav!
}

Aynı fonksiyon çağrısı, geçirilen gerçek türe bağlı olarak farklı davranışlar üretir. Bu, polimorfizmdir. MakeSound fonksiyonu bir kez yazılır ancak Speaker arayüzünü karşıladıkları sürece sınırsız sayıda türle çalışır.

Bu yaklaşım, kodunuzu esnek ve genişletilebilir tutar. Konuşan yeni bir tür eklemek, mevcut fonksiyonlarda hiçbir değişiklik gerektirmez; sadece arayüzü (interface) uygulayın, otomatik olarak çalışacaktır.

challenge icon

Görev

Kolay

Polimorfizmi iş başında gösteren bir araç açıklama sistemi kuralım. Bir arayüz (interface) aracılığıyla ortak bir davranışı paylaşan farklı araç türleri oluşturacak ve ardından herhangi bir araçla çalışan tek bir fonksiyon yazacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • vehicles.go: Bir Describe() string metodu gerektiren bir Describer arayüzü tanımlayın. Ardından, her biri bu arayüzü kendi yöntemiyle uygulayan üç araç türü oluşturun:
    • Brand ve Model alanlarına sahip CarDescribe() metodu Car: [Brand] [Model] değerini döndürür.
    • Brand ve EngineCC (int) alanlarına sahip MotorcycleDescribe() metodu Motorcycle: [Brand] [EngineCC]cc değerini döndürür.
    • Type alanına sahip (örneğin "Mountain" veya "Road") BicycleDescribe() metodu Bicycle: [Type] değerini döndürür.
  • main.go: Herhangi bir Describer kabul eden ve Describe() çağrısının sonucunu yazdıran PrintDescription adlı bir fonksiyon oluşturun. Girdiden araç detaylarını okuyun, her araç türünden birer tane oluşturun ve aynı fonksiyonun üç farklı türle de çalıştığını göstermek için her birini PrintDescription fonksiyonuna gönderin.

Aşağıdaki girdiler sağlanacaktır:

  • Satır 1: Araba markası
  • Satır 2: Araba modeli
  • Satır 3: Motosiklet markası
  • Satır 4: Motosiklet motor hacmi (tam sayı)
  • Satır 5: Bisiklet türü

Örneğin, Toyota, Camry, Honda, 600 ve Mountain verildiğinde, çıktınız şu şekilde olmalıdır:

Car: Toyota Camry
Motorcycle: Honda 600cc
Bicycle: Mountain

PrintDescription fonksiyonunun bir Car, Motorcycle veya Bicycle alıp almadığını bilmesine gerek olmadığına dikkat edin; sadece Describe() metodunu çağırır ve her tür kendi benzersiz çıktısıyla yanıt verir. İşte polimorfizm budur: tek bir fonksiyon, birden fazla davranış.

Kopya kağıdı

Polimorfizm (çok biçimlilik), farklı türlerin ortak bir arayüz aracılığıyla tek tip olarak ele alınmasını sağlar. Go'da bu, kalıtım veya sınıf hiyerarşileri olmadan arayüzler (interfaces) aracılığıyla gerçekleştirilir.

Bir fonksiyon parametre olarak bir arayüz türünü kabul ettiğinde, bu arayüzü uygulayan herhangi bir somut tür içeri aktarılabilir:

type Speaker interface {
    Speak() string
}

type Dog struct{ Name string }
func (d Dog) Speak() string { return "Woof!" }

type Cat struct{ Name string }
func (c Cat) Speak() string { return "Meow!" }

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

Aynı fonksiyon farklı türlerle çalışır:

func main() {
    dog := Dog{Name: "Rex"}
    cat := Cat{Name: "Whiskers"}
    
    MakeSound(dog)  // Woof!
    MakeSound(cat)  // Meow!
}

Fonksiyon bir kez yazılır ancak arayüzü karşıladıkları sürece sınırsız sayıda türle çalışır. Yeni türler eklemek, mevcut fonksiyonlarda herhangi bir değişiklik gerektirmez; sadece arayüzü uygulamanız yeterlidir.

Kendin dene

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// TODO: Herhangi bir Describer kabul eden ve Describe() metodunu
// çağırmanın sonucunu yazdıran PrintDescription adında bir fonksiyon oluşturun

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Araba detaylarını oku
	carBrand, _ := reader.ReadString('\n')
	carBrand = strings.TrimSpace(carBrand)
	carModel, _ := reader.ReadString('\n')
	carModel = strings.TrimSpace(carModel)

	// Motosiklet detaylarını oku
	motoBrand, _ := reader.ReadString('\n')
	motoBrand = strings.TrimSpace(motoBrand)
	motoEngineStr, _ := reader.ReadString('\n')
	motoEngineStr = strings.TrimSpace(motoEngineStr)
	motoEngine, _ := strconv.Atoi(motoEngineStr)

	// Bisiklet detaylarını oku
	bicycleType, _ := reader.ReadString('\n')
	bicycleType = strings.TrimSpace(bicycleType)

	// TODO: Giriş değerlerini kullanarak bir Car, Motorcycle ve Bicycle oluşturun

	// TODO: Polimorfizmi göstermek için her araç için PrintDescription'ı çağırın
	fmt.Println("TODO: Print vehicle descriptions")
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Yönelimli Programlama bölümündeki tüm dersler