C# Interface ve Abstract Sınıflar
C#’ta interface ve abstract sınıfları öğrenin. Farklarını, ne zaman hangisini kullanacağınızı ve tasarım senaryolarını örneklerle keşfedin.
C# dilinde abstract class ve interface, nesne yönelimli programlamada esnek ve genişletilebilir mimariler kurmak için kullanılır.
Her ikisi de ortak davranışları tanımlamaya yarar; ancak aralarında önemli farklar vardır.
abstract class kısmi bir implementasyon (kod içeren gövde) sunabilirken, interface sadece imza bildirir ve
implementasyon tamamen alt sınıflara bırakılır.
Abstract Class (Soyut Sınıf)
Soyut sınıf, abstract anahtar kelimesiyle tanımlanır ve doğrudan örneği oluşturulamaz.
Ortak özellikleri ve metotları tanımlar, fakat bazı metotlar abstract olarak işaretlenip alt sınıflara zorunlu kılınır.
Ayrıca soyut sınıflar, normal metotlar da içerebilir, yani kısmen uygulanmış davranış barındırabilir.
public abstract class Shape
{
public string Color { get; set; } = "Black";
// Alt sınıflar zorunlu olarak uygulamalı
public abstract double GetArea();
// Ortak bir metot
public void PrintColor()
{
Console.WriteLine($"Renk: {Color}");
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double GetArea()
{
return Math.PI * Radius * Radius;
}
}
Burada Shape soyut sınıfı ortak renk özelliğini sağlar,
ama GetArea() metodu alt sınıflara bırakılmıştır.
Circle sınıfı bunu kendine göre uygular.
Interface (Arayüz)
Interface, interface anahtar kelimesiyle tanımlanır.
Yalnızca metod ve property imzaları barındırır, gövde içermez (C# 8 öncesinde).
Bir sınıf birden fazla interface’i aynı anda uygulayabilir (çoklu kalıtım sağlanır).
Böylece farklı sınıflar arasında “ortak sözleşme” tanımlanır.
public interface ILogger
{
void Log(string message);
}
public class FileLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Dosyaya loglandı: {message}");
}
}
public class DbLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Veritabanına loglandı: {message}");
}
}
Burada ILogger arayüzünü uygulayan sınıflar farklı şekillerde loglama yapar.
Ama hepsi aynı metot imzasını sunmak zorundadır: Log(string).
Abstract Class vs Interface
Aralarındaki temel farklar:
- Abstract Class: Ortak davranış + zorunlu davranış tanımlayabilir. Özellik ve metot gövdeleri içerebilir.
- Interface: Sadece imza bildirir. Çoklu kalıtımı destekler.
- Abstract Class: Bir sınıf yalnızca bir soyut sınıftan türeyebilir.
- Interface: Bir sınıf birden fazla interface uygulayabilir.
- Abstract Class: Ortak alan, field ve constructor içerebilir.
- Interface: Alan veya constructor içermez.
Gerçek Hayat Senaryosu: Üretim Hattı (Interface + Abstract Class)
Aşağıdaki örnekte ürün üretim sürecini modelleyen bir IProduct arayüzü ve onu kısmen uygulayan bir
abstract class (ProductBase) tanımlanmıştır.
IProduct ortak sözleşmeyi (özellikler + metot imzaları) belirlerken, ProductBase
ortak akışı (şablon metod: Production()) ve kısmi implementasyonu sağlar.
MetalProduct, WoodProduct ve PlasticProduct sınıfları bu yapıyı özelleştirir.
Boyut için bir enum (SizeOption) kullanarak “S/M/L” gibi tutarlı değerler elde ediyoruz.
Ek olarak ürünlerin basit bir kalite kontrol arabirimi olan IQualityCheck’i de uygulamalarını sağladık.
using System;
using System.Collections.Generic;
// Boyutların standartlaştırılması için enum
public enum SizeOption
{
Small,
Medium,
Large
}
// Ortak sözleşme: Her ürünün sahip olması gereken özellik ve davranışlar
public interface IProduct
{
string Name { get; set; }
string SKU { get; set; }
SizeOption Size { get; set; }
decimal UnitCost { get; set; } // Birim maliyet
int Stock { get; set; } // Stok adedi
// Üretim akışı ve maliyet hesabı
void Production();
decimal CalculateCost(int quantity);
string GetSpecs();
}
// Basit kalite kontrol sözleşmesi
public interface IQualityCheck
{
bool QualityCheck(out string reason);
}
// ABSTRACT CLASS: Kısmi implementasyon + ortak akış (Template Method Pattern)
public abstract class ProductBase : IProduct, IQualityCheck
{
public string Name { get; set; } = string.Empty;
public string SKU { get; set; } = string.Empty;
public SizeOption Size { get; set; }
public decimal UnitCost { get; set; }
public int Stock { get; set; }
// Malzeme bazlı çarpan (alt sınıflar değiştirebilir)
protected virtual decimal MaterialFactor => 1.00m;
// Şablon metod: Üretim adımlarını sabit bir akışta çalıştırır
public void Production()
{
LogStep($"Üretim başlıyor: {Name} ({SKU})");
PrepareMaterials();
Assemble();
Finish();
LogStep("Üretim tamamlandı.\n");
}
// Baz maliyet hesaplama (alt sınıflar isterse override edebilir)
public virtual decimal CalculateCost(int quantity)
{
if (quantity <= 0) return 0m;
// Basit model: Birim maliyet * miktar * malzeme çarpanı * genel gider (10%)
decimal baseCost = UnitCost * quantity * MaterialFactor;
decimal overhead = baseCost * 0.10m;
return baseCost + overhead;
}
// Ortak teknik özellik çıktısı
public virtual string GetSpecs()
=> $"SKU: {SKU}, Boyut: {Size}, Birim Maliyet: {UnitCost:0.00} TL, Stok: {Stock}";
// Kalite kontrolün varsayılanı: maliyet ve stok mantıklı mı?
public virtual bool QualityCheck(out string reason)
{
if (UnitCost <= 0) { reason = "Birim maliyet sıfır/negatif olamaz."; return false; }
if (Stock < 0) { reason = "Stok negatif olamaz."; return false; }
reason = "OK";
return true;
}
// Alt sınıfların tamamlaması gereken adımlar
protected abstract void PrepareMaterials();
protected abstract void Assemble();
protected virtual void Finish()
{
LogStep("Genel kalite kontrol ve paketleme");
}
protected void LogStep(string message) => Console.WriteLine($" - {message}");
}
// METAL ÜRÜN
public class MetalProduct : ProductBase
{
public string Alloy { get; set; } = "Steel 304L";
public bool RequiresHeatTreatment { get; set; } = true;
protected override decimal MaterialFactor => 1.45m; // metal işleme daha maliyetli
protected override void PrepareMaterials()
{
LogStep($"Metal levha/kütük hazırlanıyor (Alaşımlı: {Alloy})");
if (RequiresHeatTreatment) LogStep("Isıl işlem için fırın hazırlığı");
}
protected override void Assemble()
{
LogStep("Kesme, bükme, kaynak ve yüzey taşlama");
if (RequiresHeatTreatment) LogStep("Isıl işlem uygulanıyor (sertleştirme)");
}
protected override void Finish()
{
LogStep("Korozyon koruması ve yüzey kaplama");
base.Finish();
}
public override string GetSpecs()
=> $"[Metal] {Name} | {base.GetSpecs()} | Alaşım: {Alloy} | Isıl işlem: {(RequiresHeatTreatment ? "Var" : "Yok")}";
public override bool QualityCheck(out string reason)
{
if (!base.QualityCheck(out reason)) return false;
// Metal için basit ek kural: Alaşım adı boş olmasın
if (string.IsNullOrWhiteSpace(Alloy)) { reason = "Alaşım bilgisi boş olamaz."; return false; }
return true;
}
}
// AHŞAP ÜRÜN
public class WoodProduct : ProductBase
{
public string WoodType { get; set; } = "Meşe";
public bool IsVarnished { get; set; } = true;
protected override decimal MaterialFactor => 1.20m;
protected override void PrepareMaterials()
{
LogStep($"Kereste seçimi ve kurutma (Tür: {WoodType})");
LogStep("Doğrama ve zımparalama");
}
protected override void Assemble()
{
LogStep("Birleştirme: geçme/dübelleme ve tutkal");
}
protected override void Finish()
{
LogStep(IsVarnished ? "Vernik uygulama" : "Yağ/koruyucu uygulama");
base.Finish();
}
public override string GetSpecs()
=> $"[Ahşap] {Name} | {base.GetSpecs()} | Ağaç türü: {WoodType} | Vernik: {(IsVarnished ? "Var" : "Yok")}";
}
// PLASTİK ÜRÜN
public class PlasticProduct : ProductBase
{
public string Polymer { get; set; } = "PP";
public bool Recyclable { get; set; } = true;
protected override decimal MaterialFactor => 0.95m; // plastik genelde daha düşük maliyet
protected override void PrepareMaterials()
{
LogStep($"Granül hammadde hazırlığı (Polimer: {Polymer})");
LogStep("Renk masterbatch karışımı");
}
protected override void Assemble()
{
LogStep("Enjeksiyon kalıplama ve çapak alma");
}
protected override void Finish()
{
LogStep("Yüzey kontrol ve etiketleme");
base.Finish();
}
public override string GetSpecs()
=> $"[Plastik] {Name} | {base.GetSpecs()} | Polimer: {Polymer} | Geri dönüştürülebilir: {(Recyclable ? "Evet" : "Hayır")}";
}
// DEMO
class Program
{
static void Main()
{
var items = new List<IProduct>
{
new MetalProduct
{
Name = "Çelik Raf",
SKU = "M-RA-001",
Size = SizeOption.Large,
UnitCost = 500m,
Stock = 40,
Alloy = "304L",
RequiresHeatTreatment = true
},
new WoodProduct
{
Name = "Ahşap Masa",
SKU = "W-MS-002",
Size = SizeOption.Medium,
UnitCost = 350m,
Stock = 12,
WoodType = "Meşe",
IsVarnished = true
},
new PlasticProduct
{
Name = "Plastik Kasa",
SKU = "P-KS-003",
Size = SizeOption.Small,
UnitCost = 80m,
Stock = 200,
Polymer = "PP",
Recyclable = true
}
};
const int qty = 10;
foreach (var p in items)
{
Console.WriteLine($"\n=== {p.Name} ===");
Console.WriteLine(p.GetSpecs());
p.Production();
Console.WriteLine($"Toplam maliyet ({qty} adet): {p.CalculateCost(qty):0.00} TL");
if (p is IQualityCheck qc)
{
Console.WriteLine(qc.QualityCheck(out var reason)
? "Kalite Kontrol: OK"
: $"Kalite Kontrol: HATA - {reason}");
}
}
}
}
Özet: IProduct arabirimi değişik ürün türleri için ortak bir sözleşme sunar.
ProductBase soyut sınıfı bu sözleşmenin ortak kısımlarını kısmen uygular ve üretim akışını (şablon metot) standartlaştırır.
Alt sınıflar (Metal/Wood/Plastic) üretimin malzemeye özel adımlarını ve maliyet varsayımlarını özelleştirir.
Böylece interface + abstract class birlikte kullanılarak hem esneklik hem de tekrar kullanılabilirlik sağlanır.
Avantajları
- Interface: Çoklu kalıtım desteği sayesinde esneklik sağlar.
- Abstract Class: Ortak alan ve kısmi implementasyon ile kod tekrarını azaltır.
- Her ikisi: Bağımlılıkları azaltır, test edilebilirliği artırır.
TL;DR
abstract class: Ortak + zorunlu davranışları tanımlar, gövde içerebilir.interface: Sadece imza bildirir, çoklu kalıtımı destekler.- Bir sınıf yalnızca bir soyut sınıftan türeyebilir ama birden fazla interface uygulayabilir.
İlişkili Makaleler
C# Delegates ve Events
C#’ta delegate ve event kavramlarını öğrenin. Olay tabanlı programlama, callback mantığı ve kullanım senaryoları örneklerle anlatılıyor.
C# Dependency Injection Temelleri
C#’ta Dependency Injection kavramını öğrenin. Bağımlılıkların yönetimi, gevşek bağlılık ve test edilebilirlik örneklerle anlatılıyor.
C# Encapsulation, Kalıtım, Polimorfizm
C#’ta encapsulation, kalıtım ve polimorfizmi öğrenin. OOP’nin temel prensiplerini örneklerle anlayıp doğru kullanımını keşfedin.
C# Extension Metotlar
C#’ta extension metotları öğrenin. Mevcut sınıfları değiştirmeden yeni metotlar eklemeyi örneklerle keşfedin.
C# ile SOLID Prensipleri
C# örnekleriyle SOLID prensiplerinin uygulanışı: daha esnek, sürdürülebilir ve test edilebilir kod tasarımları.
C# Namespace ve Assembly Kavramı
C#’ta namespace ve assembly kavramlarını öğrenin. Kodun düzenlenmesi, bağımlılık yönetimi ve proje yapısı örneklerle anlatılıyor.
C# Sınıf (Class), Object, Property ve Metotlar
C#’ta class, object, property ve metot kavramlarını öğrenin. Nesne yönelimli programlamanın temel yapı taşları örneklerle açıklanıyor.
Sealed, Static ve Partial Class Kullanımı in C#
C#’ta sealed, static ve partial class kavramlarını öğrenin. Amaçları, farkları ve kullanım senaryoları örneklerle anlatılıyor.