Ana içeriğe geç

Yan yana

Soyut SınıfvsInterface

Soyut sınıf ile interface arasındaki fark nedir?

Güncellendi 2 dk okuma8 fark

Kısaca

Soyut sınıf, alt sınıflarıyla kod ve durum paylaşır; interface ise yalnızca bir türün neler yapabildiğini bildirir ve bir sınıf birçoğunu uygulayabilir.

Soyut Sınıf

Soyut sınıf, tek başına örneklenemeyen bir sınıftır; alt sınıflarıyla kod paylaşır ve her alt sınıfın gerçekleştirmesi gereken metotları bildirir.

Soyut Sınıf sayfasını oku

Interface

Arayüz

Interface, bir türün sağlamayı vaat ettiği metot ve özellik imzalarından oluşan adlandırılmış bir kümedir; bu üyelerin nasıl gerçekleştirildiğini söylemez.

Interface sayfasını oku

Soyut Sınıf ve Interface karşılaştırması

ÖzellikSoyut SınıfInterface
Amacıİlişkili sınıflar arasında kod ve durum paylaşmakBir türün neler yapabildiğini tarif etmek
Sınıf başınaBir tane (Java, C# ve TypeScript'te)Gerektiği kadar
MetotlarSoyut metotlar ve eksiksiz yazılmış metotlarİmzalar; Java 8 ve C# 8'den beri varsayılan gövdeler
AlanlarKendi değerleri olan örnek alanlarıÖrnek durumu yok; en fazla sabitler ya da özellik bildirimleri
Yapıcı metotVar; alt sınıflar onu super ile çağırırYok
Üye erişimiprotected ve private üyeler kullanabilirÜyeler varsayılan olarak public'tir
İlişki“-dir” (is-a): bir Circle bir Shape'tir“yapabilir” (can-do): bir Circle Printable'dır
TypeScript'te çalışma zamanındaGerçek bir JavaScript sınıfına derlenirSilinir; yalnızca tip denetimi için vardır

Fark, açıklamalı

Soyut sınıf, tek başına örneklenemeyen, genişletilmek için var olan bir sınıftır. Alanlar, bir yapıcı metot ve eksiksiz yazılmış metotlar barındırabilir; bunların yanında gövdesi olmayan ve her alt sınıfın yazması gereken soyut metotlar da bulunur. Interface ise adlandırılmış bir sözleşmedir: bir türün sağlamayı vaat ettiği metot imzalarının, bazen de özelliklerin listesidir ve kendine ait bir durum tutmaz.

Asıl fark şudur: soyut sınıf, ilişkili türlerin bir işi nasıl yaptığını paylaşır; interface ise bir türün ne yapabildiğini tarif eder. Java, C# ve TypeScript'te bir sınıf yalnızca bir sınıfı genişletebilir ama birçok interface uygulayabilir; bu yüzden soyut sınıf bir türün tek bir ailedeki yerini sabitler, interface'ler ise serbestçe birleştirilebilir: bir Circle hem HasArea hem de Printable olabilir. Soyut sınıflar, temel sınıfın describe() metodunu bir kez yazıp area() metodunu her alt sınıfa bıraktığı template method (şablon metot) desenine uygundur.

İkisi çoğu zaman birlikte çalışır. Yaygın bir tasarım, sözleşmeyi bir interface olarak tanımlar ve onun bir kısmını uygulayan bir soyut sınıfı kullanışlı bir temel olarak ekler; Java'nın List interface'i ve AbstractList sınıfı buna örnektir. Diğer kod yalnızca interface'e bağlı olur; böylece testlerdeki sahte bir uygulama dahil her uygulama verilebilir, ilişkili uygulamalar da kodu soyut sınıf üzerinden paylaşmaya devam eder.

Sık yapılan bir yanlış, Java 8 ve C# 8 interface'lerin varsayılan metot gövdeleri içermesine izin verdiğinde farkın ortadan kalktığı düşüncesidir. Örnek alanları (instance field) ve yapıcı metotlar hâlâ yalnızca sınıflara aittir ve bir sınıf hâlâ yalnızca bir sınıfı genişletebilir. Diller de farklıdır: TypeScript interface'leri derlemeden sonra kaybolur; Python'da ise interface anahtar sözcüğü yoktur, onun yerine abc modülündeki soyut temel sınıflar ya da typing.Protocol kullanılır.

Hangisini kullanmalısınız?

Soyut Sınıf şu durumlarda doğru seçim:

  • İlişkili sınıflar yalnızca metot adlarını değil, gerçek kodu ya da alanları paylaşıyor.
  • Bir temel sınıfın bir algoritmanın adımlarını sabitlemesini ve bazılarını alt sınıflara bırakmasını istiyorsunuz.
  • Alt sınıfların ortak bir yapıcı metoda ya da protected yardımcı metotlara ihtiyacı var.

Interface şu durumlarda doğru seçim:

  • Birbiriyle ilişkisiz sınıflar, karşılaştırılabilir ya da yazdırılabilir olmak gibi aynı yeteneği sunmalı.
  • Bir sınıfın aynı anda birkaç sözleşmeyi yerine getirmesi gerekiyor.
  • Uygulamaları değiştirebilmek istiyorsunuz; örneğin testlerde sahte bir uygulama kullanmak için.
  • Yalnızca bir nesnenin ya da bir API'nin şeklini tarif etmeniz gerekiyor.

TypeScript'te şekiller: tek bir soyut temel sınıf ya da birkaç interface

Soyut Sınıftypescript
// Abstract class: shared code, plus gaps each subclass fills
abstract class Shape {
  constructor(public readonly name: string) {}
  abstract area(): number;            // no body
  describe() { return `${this.name}: ${this.area().toFixed(1)}`; }
}

class Circle extends Shape {          // extends exactly one class
  constructor(private r: number) { super("circle"); }
  area() { return Math.PI * this.r ** 2; }
}
Interfacetypescript
// Interfaces: contracts only, and a class can take several
interface HasArea { area(): number; }
interface Printable { print(): string; }

class Circle implements HasArea, Printable {
  constructor(private r: number) {}
  area() { return Math.PI * this.r ** 2; }
  print() { return `circle: ${this.area().toFixed(1)}`; }
}

// Any object with the right shape fits, class or not
const square: HasArea = { area: () => 4 };

Sık sorulan sorular

Bir sınıf aynı anda hem soyut bir sınıfı genişletip hem de interface uygulayabilir mi?

Evet. Java ya da TypeScript'te class Circle extends Shape implements Printable yazarsınız: bir temel sınıf ve istediğiniz sayıda interface.

Interface'ler varsayılan metotlar içerebiliyorsa neden soyut sınıf kullanılır?

Çünkü interface'ler hâlâ örnek alanları ya da yapıcı metotlar tutamaz. İlişkili sınıflar durum, hazırlık mantığı ya da protected yardımcılar paylaşıyorsa bunların yeri soyut sınıftır.

Python'da interface var mı?

Anahtar sözcük olarak yok. Bu rolü abc modülündeki soyut temel sınıflar üstlenir; typing.Protocol ise tip denetleyicilerinin, TypeScript ve Go'daki gibi şekle göre eşleştirdiği interface'leri tarif eder.

Daha fazla

Ayarlar