Interface ve Abstract Class — Rol mü, İskelet mi?
Önce şunu oku: Polimorfizm ve Dinamik Bağlama — Kararı Kim Veriyor?
30 saniyede özet
Interface bir roldür: bir sınıf aynı anda birkaç rol üstlenebilir. Abstract class ise ortak iskelet ve veri verir, ama bir sınıf yalnızca bir tanesinden türeyebilir. Emin değilsen interface ile başla.
Herkesin uyduğu bir sözleşmeye tek bir madde ekledin. Ertesi sabah telefonun susmuyor.
-
Bayt: Ödeme sözleşmesine küçücük bir madde ekledim: para iadesi.
-
Sen: Ne kadar masum bir değişiklik.
-
Bayt: Ertesi sabah üç ekip birden arıyor!
-
Bayt: Sözleşmeye madde eklemenin de bir usulü var. Önce şunu soralım: rol mü, soy mu?
Java’da o sözleşme ödeme yöntemlerinin ortak interface’iydi ve eklenen madde refund(). Abstract class’a çevirmek de çare değil: zaten başka bir sınıftan türeyen bir ödeme yöntemi dışarıda kalır.
İkisi de söz verir, farkı ne?
| Interface | abstract classDoğrudan örneklenemeyen, alt sınıflara ortak durum, constructor ve kod sağlayabilen sınıf. Bir sınıf yalnızca bir abstract class'ı genişletebilir.Sözlükte gör → | |
|---|---|---|
| Bir sınıf kaç tane alabilir | İstediği kadar | Yalnızca bir tane |
| Örnek durumu (alan) | Yok; yalnızca sabit | Var |
| Constructor | Yok | Var |
| Gövdeli metot | default, static, private | Her tür |
Rol tanımlamak için ilk tercih interface’tir. Birkaç sınıfın gerçekten ortak verisi ve ortak kodu varsa, interface’in yanına onu uygulayan bir abstract sınıf eklenir. Java’daki List ve AbstractList tam böyle bir ikilidir.
Kafam karıştı, daha basit anlat
Interface bir rol tanımıdır: “şoför araba sürebilir”. Abstract class ise yarı kurulmuş bir iskelettir. Önce rolü yaz, ortak kod gerçekten varsa iskeleti ekle.
Interface ile abstract class arasındaki en önemli pratik fark hangisi?
Bir interface'e `int retryCount = 0;` yazdın. Bu nedir?
Bir sözleşmeyi değiştirmek
Başka ekiplerin uyguladığı PaymentMethod interface'ine gövdesiz refund() metodunu eklersen ne olur? Cevabı göster
Bütün uygulamalar derlenmez hâle gelir. Yayınlanmış bir interface’e abstract metot eklemek kırıcı bir değişikliktir.
Adım adım oku
- CardPayment yalnızca tek bir sınıftan, PaymentBase'den türeyebilir. Bu onun soyudur.
- Ama istediği kadar interface uygular: PaymentMethod, Loggable, Auditable. Bunlar onun rolleridir.
- PaymentMethod'a gövdesiz bir refund() eklenirse, onu uygulayan her ekibin kodu derlenmez olur.
- Aynı metot default bir gövdeyle eklenirse var olan uygulayıcılar kırılmaz; isteyen kendi sürümünü yazar.
Java 8’den beri interface’teki bir metodun hazır bir gövdesi olabilir: default methodJava 8'den beri bir interface'in gövdesiyle birlikte tanımlayabildiği metot. Mevcut uygulamaları kırmadan sözleşmeyi genişletmeye yarar; örnek durumuna erişemez.Sözlükte gör →. Java ekibi stream() ve forEach’i koleksiyonlara bu sayede, dünyadaki hiçbir kodu kırmadan ekledi.
Default gövde, interface’i uygulayan herkes için mantıklı olmalı. Kendi verisi olamaz; yalnızca interface’in diğer metotlarını çağırabilir.
Aşağıda aynı hikâyenin kodu var: bir bankanın ödeme yöntemleri ve sonradan eklenen iade. Otomatik iadesi olmayan yöntem kırılmaz. Default gövde iadeyi operasyon ekibinin elle işleyeceği kuyruğa yönlendirir.
Derinleş · Ödeme yöntemleri: rol, soy ve sonradan gelen iade 5 dosya · ~96 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
Bir sözleşmeye yeni bir madde eklersen, imzalayan herkes onu yerine getirmek zorunda kalır. Default metot, maddeyi hazır bir cevapla ekler; kimse zorlanmaz.
Başka ekiplerin uyguladığı yayınlanmış bir interface'e gövdesiz yeni bir metot eklersen ne olur?
Her ihtiyaç için hangisi daha uygun?
Kendin gör
Interface mi, abstract class mı — sözleşme değişince ne olur?
Tohum 324775public interface PaymentMethod { Receipt pay(Money amount); Receipt refund(Receipt r); // YENİ, gövdesiz} class CardPayment implements PaymentMethod { … }class WalletPayment implements PaymentMethod { … }class LegacyTransfer extends BankClient /* + PaymentMethod? */ { … }- CardPaymentbekliyor
- WalletPaymentbekliyor
- LegacyTransferbekliyor
Şu an ne oldu?
Üç uygulama, üç ayrı ekip
CardPayment ve WalletPayment sade sınıflar. LegacyTransfer zaten BankClient'ı genişletiyor.
Görevler0/3
Tek bir değişiklikle bütün uygulamaları kıraçık
İpucu
Yayınlanmış bir sözleşmeye gövdesiz bir metot eklersen?
Hiçbir uygulamayı kırmadan yeni bir metot ekleaçık
İpucu
Java 8'den beri interface metotlarının bir gövdesi olabilir.
Bir uygulamanın sözleşmeye hiç katılamadığı bir tasarım seçaçık
İpucu
Zaten başka bir sınıfı genişleten biri, ikinci bir sınıfı genişletebilir mi?
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Gövdesiz refund(): üç uygulama da kırıldı.
- “interface + default metot” seç. Hiçbiri kırılmadı.
- “abstract class” seç. Yeni metot sorunsuz, ama LegacyTransfer baştan beri dışarıda.
- Değişikliği “ortak durum” yap. Interface’ler durum taşıyamıyor.
- “İkinci rol” seç. Interface’le herkes iki rolü birden üstleniyor.
Her servis sınıfı için tek uygulamalı bir interface yazılıyor: `OrderService` + `OrderServiceImpl`. Bu ne zaman gereksizdir?
Satır satır: iki default çakışınca
Java belirsizliği senin yerine çözmez
interface Scanner { default String name() { return "tarayıcı"; } }interface Printer { default String name() { return "yazıcı"; } } class OfficeDevice implements Scanner, Printer { @Override public String name() { return Printer.super.name() + " + " + Scanner.super.name(); }}Debug
derleyici OfficeDevice name()'i iki interface'ten birden devralıyor. İkisi de default.
- adaylar
- = Scanner.name, Printer.name
Sol/sağ ok tuşlarıyla da gezebilirsin.
İki interface aynı isimde iki farklı default gövde getirirse Java hangisini seçeceğini bilemez. Buna diamond problemBir sınıfın, aynı imzalı default metodu sağlayan iki interface'i birden uygulaması. Java bunu belirsiz sayar ve sınıfın metodu açıkça override etmesini ister.Sözlükte gör → denir. Kural basit: sınıfın kendi yazdığı kazanır; çatışma varsa sınıf metodu yazıp kararı kendisi verir.
Kafam karıştı, daha basit anlat
İki arkadaş sana aynı soruya farklı cevap verdiyse, hangisini seçeceğine sen karar verirsin. Java da aynısını ister: sınıf, çakışan metodu kendisi yazar.
Program ne yazdırır?
Tuzaklar
Alışkanlıkla interface açmak. OrderService ve OrderServiceImpl ikilisinin ikinci bir uygulaması yoksa, interface yalnızca fazladan bir dosya ve bir atlama ekler.
Default metoda iş mantığı doldurmak. Interface gizlice bir taban sınıfa dönüşür ve kalıtımın kırılganlık sorunu da onunla birlikte gelir.
Interface’te “alan” sanmak. Interface’e yazılan int retryCount = 0; herkesin paylaştığı bir sabittir, her sınıfa ait bir sayaç değil.
Record’u bir sınıftan türetmeye çalışmak. Record’lar başka bir sınıftan türeyemez. Kapalı bir tip ailesi istiyorsan sealed interface kullan.
Bu sınıf derlenmiyor. Hangi satır sorunun kaynağı ve nasıl düzeltilir?
Kendini sına
Bir sınıf birden fazla interface uygulayabilir.
Bir interface'e iş mantığı içeren büyük default metotlar eklenmeye başlandı; metotlar birbirini ve getter'ları çağırıyor. Risk ne?
Aklında kalacak üç şey
- 1 Bir sınıf birçok interface uygulayabilir ama yalnızca tek bir sınıftan türeyebilir. Rol tanımlarken ilk tercih interface'tir.
- 2 Kullanılan bir interface'e gövdesiz yeni metot eklemek onu uygulayan herkesi kırar. Default metot kırmadan genişletir ama veri tutamaz.
- 3 İki interface aynı default metodu getirirse Java seçim yapmaz; sınıf metodu kendisi yazar ve hangisini istediğini açıkça söyler.
3 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.
- Nesne Yönelimli ProgramlamaSoyutlama ve Dört Sütun — Hangi Değişikliğe Hangisi Yardım Eder?Kapsülleme, soyutlama, kalıtım, polimorfizm. Dördü de aynı soruya cevap: bir şey değişince kaç dosya değişir?Derse git
- Core Java & EşzamanlılıkAnnotation ve Reflection — Spring'in Sihri Nasıl Çalışır?@Service yazdın ve Spring o sınıfı kendi kendine buldu. Bir satır not bunu nasıl yapıyor?Derse git