Yükleniyor...

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:


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ı


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# 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ı.