Soyut Sınıflar ve Arayüzler
Coddy'nin Java Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 38 / 87.
Artık hem soyut sınıfları hem de arayüzleri anladığınıza göre, yaygın bir soru ortaya çıkıyor: birini diğerine ne zaman tercih etmelisiniz? Seçim, neyi modellemeye çalıştığınıza bağlıdır.
Sınıflar, paylaşılan bir durum veya davranışa sahip ortak bir temeli paylaştığında bir soyut sınıf (abstract class) kullanın. Soyut sınıflar; örnek değişkenlerine, yapılandırıcılara ve soyut ile somut metotların bir karışımına sahip olabilir:
public abstract class Animal {
protected String name; // paylaşılan durum
public Animal(String name) {
this.name = name;
}
public void sleep() { // paylaşılan davranış
System.out.println(name + " is sleeping");
}
public abstract void makeSound(); // uygulanmalıdır
}İlişkisiz sınıfların paylaşabileceği bir yetenek tanımlamak istediğinizde bir interface kullanın. Interface'ler bir nesnenin ne olduğuna değil, ne yapabildiğine odaklanır:
public interface Flyable {
void fly();
}
// İlişkisiz sınıflar bu yeteneği paylaşabilir
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }İşte hızlı bir karşılaştırma:
| Özellik | Abstract Class | Interface |
|---|---|---|
| Örnek değişkenleri | Evet | Sadece sabitler |
| Yapıcılar (Constructors) | Evet | Hayır |
| Çoklu kalıtım | Hayır (tekli extends) | Evet (çoklu implements) |
| Erişim belirleyicileri | Herhangi biri | Sadece public (soyut metotlar için) |
Pratik bir kural: Kendinizi yalnızca soyut metotları olan ve durumu (state) bulunmayan bir abstract class oluştururken bulursanız, bir interface muhtemelen daha iyi bir seçimdir.
Görev
KolaySoyut sınıfların ne zaman kullanılacağını ve arayüzlerin (interfaces) ne zaman kullanılacağını gösteren bir araç sistemi oluşturalım. Ortak durum ve davranışları paylaşan araçları bir soyut sınıf aracılığıyla modelleyecek, isteğe bağlı yetenekleri ise arayüzler aracılığıyla ekleyeceksiniz.
Kodunuzu beş dosya halinde düzenleyeceksiniz:
Vehicle.java: Tüm araçlar için temel teşkil eden soyut bir sınıf oluşturun. Her aracın birbrandalanı (String) ve biryearalanı (int) vardır. Her iki alanı da başlatan bir yapıcı (constructor), her biri için getter metotları ve String döndüren soyut birstartEngine()metodu ekleyin. Ayrıca şu formatta değer döndüren somut birgetInfo()metodu ekleyin:[brand] ([year]). Bu, soyut bir sınıf için mükemmel bir kullanım örneğidir; araçlar durumu (brand, year) ve bazı davranışları (getInfo) paylaşır, ancak her biri motorunu farklı şekilde çalıştırır.Convertible.java: Tavanı açılıp kapanabilen araçlar için bir arayüz tanımlayın. Bu yetenek bir aracın ne olduğuyla ilgili değil, belirli araçların yapabildiği bir şeydir. Her ikisi de String döndüren iki metot bildirin:openRoof()vecloseRoof().Car.java:Vehiclesınıfını genişleten veConvertiblearayüzünü uygulayan bir sınıf oluşturun. Bir Car'ın ek birnumDoorsalanı (int) vardır. Devralınan alanları başlatmak içinsuperkullanın.startEngine()metodunu[brand] car engine starteddöndürecek şekilde uygulayın.openRoof()metodunu[brand] roof openingvecloseRoof()metodunu[brand] roof closingdöndürecek şekilde uygulayın.Motorcycle.java:Vehiclesınıfını genişleten ancakConvertiblearayüzünü uygulamayan bir sınıf oluşturun; motosikletlerin tavanı yoktur! Bir Motorcycle'ınhasSidecaralanı (boolean) vardır.startEngine()metodunu[brand] motorcycle engine roaringdöndürecek şekilde uygulayın.Main.java: Soyut sınıflar ve arayüzler arasındaki farkı göstermek için her şeyi bir araya getirin. Dört girdi alacaksınız: bir araba markası, bir araba yılı, bir motosiklet markası ve bir motosiklet yılı.Bir Car (4 kapılı) ve bir Motorcycle (sepeti olmayan) oluşturun. İlk olarak, her iki araç için
getInfo()çıktısını yazdırarak paylaşılan soyut sınıf davranışını gösterin; her ikisi de bunu Vehicle sınıfından devralır. Ardından her biri içinstartEngine()sonucunu yazdırın; her araç tipinin bunu nasıl farklı şekilde uyguladığına dikkat edin.Son olarak, arayüz yeteneğini gösterin: Sadece Car sınıfı
Convertiblearayüzünü uyguladığı için, sadece araba üzerindeopenRoof()ve ardındancloseRoof()metotlarını çağırın ve yazdırın.
Dört girdi alacaksınız: araba markası (String), araba yılı (int), motosiklet markası (String) ve motosiklet yılı (int).
Çıktınız toplam altı satır olmalıdır. Her iki aracın da soyut sınıfın durumunu ve getInfo() metodunu nasıl paylaştığına, ancak yalnızca Car'ın üstü açılabilir (convertible) yeteneğine sahip olduğuna dikkat edin; bu, her bir yaklaşımın ne zaman kullanılacağını gösterir!
Kopya kağıdı
Sınıflar ortak bir durum veya davranışa sahip ortak bir temeli paylaştığında bir soyut sınıf (abstract class) kullanın. Soyut sınıflar örnek değişkenlerine, yapıcılara (constructors) ve soyut ile somut metotların bir karışımına sahip olabilir:
public abstract class Animal {
protected String name; // paylaşılan durum
public Animal(String name) {
this.name = name;
}
public void sleep() { // paylaşılan davranış
System.out.println(name + " is sleeping");
}
public abstract void makeSound(); // uygulanmalıdır
}İlişkisiz sınıfların paylaşabileceği bir yetenek tanımlamak istediğinizde bir arayüz (interface) kullanın. Arayüzler bir nesnenin ne olduğuna değil, ne yapabildiğine odaklanır:
public interface Flyable {
void fly();
}
// İlişkisiz sınıflar bu yeteneği paylaşabilir
class Bird extends Animal implements Flyable { ... }
class Airplane implements Flyable { ... }
class Drone implements Flyable { ... }| Özellik | Soyut Sınıf (Abstract Class) | Arayüz (Interface) |
|---|---|---|
| Örnek değişkenleri | Evet | Sadece sabitler |
| Yapıcılar (Constructors) | Evet | Hayır |
| Çoklu kalıtım | Hayır (tekli extends) | Evet (çoklu implements) |
| Erişim belirleyiciler | Herhangi biri | Sadece public (soyut metotlar için) |
Kılavuz: Eğer sadece soyut metotları olan ve hiçbir durumu (state) bulunmayan bir soyut sınıf oluşturuyorsanız, muhtemelen bir arayüz daha iyi bir seçimdir.
Kendin dene
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Girdileri oku
String carBrand = scanner.nextLine();
int carYear = scanner.nextInt();
scanner.nextLine(); // satır sonu karakterini tüket
String motorcycleBrand = scanner.nextLine();
int motorcycleYear = scanner.nextInt();
// TODO: 4 kapılı bir Araba (Car) oluşturun
// TODO: Sepeti olmayan (false) bir Motosiklet (Motorcycle) oluşturun
// TODO: Her iki araç için getInfo() metodunu yazdırın (paylaşılan soyut sınıf davranışını gösterir)
// TODO: Her iki araç için startEngine() metodunu yazdırın (farklı uygulamaları gösterir)
// TODO: Sadece araba için openRoof() ve closeRoof() metodlarını yazdırın (arayüz yeteneğini gösterir)
}
}
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
1OOP Temelleri
Harici DosyalarOOP'ye GirişSınıflar ve Nesnelerthis Anahtar KelimesiMetotlarAlanlar (Öznitelikler)Yapıcı MetotYapıcı Metot Aşırı YüklemeÖzet - Basit Hesap Makinesi4Kalıtım
Temel Kalıtım (extends)super Anahtar KelimesiMetot Geçersiz Kılma (@Override)Yapıcı Metot ZincirlemeObject SınıfıTekli ve Çok Seviyeli KalıtımNeden Çoklu Sınıf Kalıtımı Yok?Özet - Çalışan Hiyerarşisi7Özel Metotlar ve Object Sınıfı
toString() Metoduequals() ve hashCode()clone() MetoducompareTo() ve ComparableComparator ArayüzüÖzet - Özel Sıralama2Erişim Belirleyiciler ve Kapsülleme
Erişim Seviyelerine Genel BakışGetter ve Setter MetotlarıBilgi Gizlemefinal Anahtar KelimesiÖzet - Banka Hesabı Yöneticisi5Polimorfizm
Metot Aşırı Yükleme TemelleriMetot Geçersiz Kılma (Çalışma Zamanı)Upcasting ve Downcastinginstanceof OperatörüSoyut Sınıflar ve MetotlarÖzet - Şekil Hesaplayıcı8İleri Düzey OOP Kavramları
Kompozisyon vs KalıtımAgregasyon vs KompozisyonDahili, Yuvalanmış ve Anonim SınıflarEnum'lar ve Enum MetotlarıRecords (Java 16+)Sealed Classes (Java 17+)11Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıBuilder KalıbıObserver KalıbıStrategy Kalıbı14Final Meydan Okumaları
E-Öğrenme PlatformuBankacılık SistemiOyun Karakteri GeliştirmeAraç Kiralama Servisi3Sınıf Özellikleri ve Statik Üyeler
Instance ve Statik DeğişkenlerStatik MetotlarStatik BloklarSabitler (static final)Özet - Sayaç ve Utility6Arayüzler ve Soyut Sınıflar
Arayüzlere GirişArayüzleri UygulamaÇoklu Arayüz UygulamaArayüzlerde Default ve StaticSoyut Sınıflar ve ArayüzlerFonksiyonel ArayüzlerÖzet - Ödeme Sistemi9Generics
Generics'e GirişGeneric SınıflarGeneric MetotlarSınırlandırılmış Tip ParametreleriWildcard'lar (?, extends, super)Özet - Generic Container12Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıYineleyici Kalıbı