Behavioral — Davranışsal Desenler

Template Method

Şablon Metot Deseni

Amaç: Bir algoritmanın iskeletini üst sınıfta tanımlamak, bazı adımlarının uygulanmasını ise alt sınıflara bırakmak.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Çay ve kahve yapmayı düşünün. İkisinin de tarifi aslında çok benzer:

  1. Suyu kaynat
  2. İçeceği demle (çay: demliğe çay koy / kahve: filtreden geçir)
  3. Bardağa dök
  4. Eklemeleri yap (çay: limon / kahve: süt ve şeker)

Birinci ve üçüncü adımlar her zaman aynı. Sadece ikinci ve dördüncü adımlar içeceğe göre değişiyor. Sıralama da hiç değişmiyor: bardağa dökmeden önce demlemek zorundasınız.

Ev inşaatı

Bir müteahhit firmanın ev yapım süreci sabittir: temel → duvarlar → çatı → iç tasarım. Ama müşteri ahşap ev mi, betonarme ev mi istediğine göre duvar ve çatı adımları farklı uygulanır.

Template Method şunu der: "Sıralamayı ben belirlerim; sen sadece farklı olan adımları doldur."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Template Method, algoritmanın adımlarını sırasıyla çağıran (genellikle virtual olmayan) bir şablon metot içeren soyut bir sınıftır. Değişen adımlar abstract (zorunlu) veya virtual (opsiyonel, hook) metotlar olarak bırakılır.

Adım türleri

Hollywood Prensibi

"Bizi aramayın, biz sizi ararız." Alt sınıflar üst sınıfı çağırmaz; üst sınıfın şablon metodu, uygun zamanda alt sınıfın adımlarını çağırır. Bu, framework'lerin temel çalışma prensibidir.

.NET'te tanıdık örnekler

Strategy'den farkı

Template Method kalıtım ile algoritmanın bir kısmını değiştirir (derleme zamanında). Strategy composition ile algoritmanın tamamını değiştirir (çalışma zamanında).

Dezavantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Farklı formatlarda (CSV, JSON) veri içe aktaran bir sistem. Okuma ve ayrıştırma formata göre değişiyor; doğrulama, kaydetme ve raporlama sırası ise her zaman aynı.

Adım 1 Soyut sınıf ve şablon metot

Import metodu algoritmanın iskeletidir ve override edilemez (virtual değil). Değişen adımlar alt sınıflara bırakılmıştır.

public abstract class DataImporter
{
    // ŞABLON METOT: sıralama burada sabitlenir.
    public void Import(string source)
    {
        Console.WriteLine($"[{GetType().Name}] içe aktarma başladı");
        string raw = ReadData(source);                 // abstract
        List<string> records = Parse(raw);             // abstract
        var valid = records.Where(Validate).ToList();  // varsayılan davranış
        Save(valid);                                   // ortak adım
        if (ShouldNotify()) Notify(valid.Count);       // hook
        Console.WriteLine();
    }

    protected abstract string ReadData(string source);
    protected abstract List<string> Parse(string raw);

    protected virtual bool Validate(string record) => !string.IsNullOrWhiteSpace(record);

    protected virtual bool ShouldNotify() => false;    // hook: varsayılan kapalı

    private void Save(List<string> records) =>
        Console.WriteLine($"  Kaydedildi: {string.Join(" | ", records)}");

    private void Notify(int count) =>
        Console.WriteLine($"  E-posta gönderildi: {count} kayıt aktarıldı.");
}

Adım 2 Alt sınıflar: sadece farklı olan adımları doldurur

public class CsvImporter : DataImporter
{
    protected override string ReadData(string source)
    {
        Console.WriteLine($"  CSV dosyası okunuyor: {source}");
        return "Ali;30\n;\nAyşe;25";
    }

    protected override List<string> Parse(string raw) =>
        raw.Split('\n').Select(line => line.Trim(';')).ToList();
}

public class JsonImporter : DataImporter
{
    protected override string ReadData(string source)
    {
        Console.WriteLine($"  API'den JSON alınıyor: {source}");
        return "[\"Mehmet\",\"\",\"Zehra\",\"X\"]";
    }

    protected override List<string> Parse(string raw) =>
        System.Text.Json.JsonSerializer.Deserialize<List<string>>(raw)!;

    // Varsayılan doğrulamayı genişlet: en az 2 karakter olsun.
    protected override bool Validate(string record) =>
        base.Validate(record) && record.Length >= 2;

    protected override bool ShouldNotify() => true;    // hook'u aç
}

Adım 3 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

DataImporter[] importers = { new CsvImporter(), new JsonImporter() };

importers[0].Import("musteriler.csv");
importers[1].Import("https://api.ornek.com/users");

Konsol çıktısı

[CsvImporter] içe aktarma başladı
  CSV dosyası okunuyor: musteriler.csv
  Kaydedildi: Ali;30 | Ayşe;25

[JsonImporter] içe aktarma başladı
  API'den JSON alınıyor: https://api.ornek.com/users
  Kaydedildi: Mehmet | Zehra
  E-posta gönderildi: 2 kayıt aktarıldı.

Kodda dikkat edilmesi gerekenler

Özetle: Template Method, algoritmanın sırasını üst sınıfta sabitler ve değişen adımları alt sınıflara bırakır; kod tekrarını önler.
← Ana sayfaya dön