Façade Design Pattern

Façade tasarım deseni

Selam millet!

Hiç düşündünüz mü; hayatımızda kullandığımız cihazların yaptığı işler gittikçe daha karmaşık bir hale geliyor. Fakat buna rağmen, kullanım şekilleri oldukça basitleşiyor. Bu durum, sanırım adı konulmamış bir mühendislik prensibi. Arkada yapılan iş ne kadar karmaşık olursa olsun, ürünün kullanımı basit olsun.

Mesela tam otomatik bir çamaşır makinesini ele alın. Kullanıcı, deterjan ve yumuşatıcı gibi malzemeleri hazırladıktan sonra çamaşır tipini seçer ve makineyi çalıştırır. Çamaşır makinasının bu noktadan sonra ne yapacağına kendisi karar verir. Değerleri ölçer, süreci yönetir ve hangi sırayla hangi işlemleri yapacağını bilir. Tüm bunları adı üzerinde “otomatik” bir biçimde yapar.

Peki, bizim geliştirdiğimiz yazılım uygulamalarında da aynı yaklaşım söz konusu olamaz mı? Birden fazla nesnenin kullanıldığı karmaşık bir işlemi, nesneleri bir araya getirerek “otomatik” bir biçimde çalıştıracak bir sınıf inşa edemez miyiz?

Tabii ki ederiz! Ve hatta eminim ki birçoğunuz, “e zaten ben yapıyorum ki” diye yanıtlamış bile olabilir bu soruyu. O zaman söyleyelim. Bu kullandığınız yöntem bir tasarım desenidir ve adı da Façade Design Pattern’dir.

Adını, Fransızca “cephe – ön yüz” anlamına gelen bir kelime bu arada Façade. Fransızcadan olduğu gibi İngilizceye de geçmiş. Kelimeyi dilbilimsel açıdan ele almayacağım tabi ama o “ç” harfinin gerçekten kelimede olduğunu belirtmek istedim.

Her neyse… Tahmin edeceğiniz gibi bu desen, uygulama geliştiriciler tarafından oldukça sık kullanılıyor. O halde biz de bir senaryo belirleyelim ve kod örneğimizi yazmaya girişelim.

Senaryomuz, bir e-ticaret uygulaması üzerinde sipariş algoritması olsun (Tamam biliyorum çok klişe ama basit ve anlaşılır ne yapayım). Kullanıcı sepetini oluşturduktan sonra ödeme ve kargo bilgilerini de girerek tek tuşla siparişini verir. Oysa bilen bilir arkada neler olduğunu!

  1. Bankaya gerekli bilgileri gönder ve onay al.
  2. Müşteri nesnesini oluştur.
  3. Seçilen kargo şirketini de nesne olarak oluştur.
  4. Oluşturulan siparişi veritabanına ekle ve yeni Sipariş id’sini bellekte tut.
  5. Yeni sipariş id’si ile satın alınan tüm ürünleri ilişkilendir ve veritabanına ekle.
  6. Satın alınan ürünlerin stoklarını güncelle.
  7. İşlemi tamamla.

Bu yedi adımın da farklı nesnelerin sorumluluğunda olduğunu düşünürsek, her sipariş verme işleminde bu adımları tekrar tekrar kurgulamak işimizi oldukça karmaşıklaştırır. Bunun yerine tüm bu adımları yerine getiren bir nesne inşa edebilirsiniz. İşte o nesneniz Façade olur!

Hadi önce modellerimizi oluşturalım:

 public class Musteri
    {
        public int Id { get; set; }
        public string Ad { get; set; }
        public string Soyad { get; set; }
    }
    public class SepettekiUrun
    {
        public int Id { get; set; }
        public string UrunAdi { get; set; }
        public int Adet { get; set; }
        public decimal Fiyat { get; set; }
    }
    public class KargoSirketi
    {
        public int Id { get; set; }
        public string Ad { get; set; }
        public string Iletisim { get; set; }
    }

 

Tamamdır. Şimdi de gerekli operasyonların sorumluluğunu üstlenecek business sınıfları gelsin:

 public class SiparisIslemleri
    {
        public int SiparisEkle(DateTime siparisTarihi, Musteri musteri, KargoSirketi kargoSirketi)
        {
            Console.WriteLine("{0} tarihinde {1} isimli müşteri siparişi eklendi. Seçilen kargo şirketi:{2} ", siparisTarihi.ToString(), musteri.Ad, kargoSirketi.Ad);
            return 1;
        }
    }

    public class SiparisDetaylari
    {
        public void SiparisDetaylariniEkle(int siparisId, List<SepettekiUrun> urunler)
        {
            Console.WriteLine("{0} numaralı siparişte alınan ürünler:", siparisId);
            Console.WriteLine("...............................");
            urunler.ForEach(u => Console.WriteLine("{0} ürününden {1} adet alındı. Ara toplam:{2}", u.UrunAdi, u.Adet, u.Adet * u.Fiyat));
            Console.WriteLine("...............................");
            var toplam = urunler.Sum(x => x.Fiyat * x.Adet);
            Console.WriteLine("Toplam:{0}", toplam);

        }
    }


    public class UrunIslemleri
    {
        public void StokGuncelle(int urunId, int adet)
        {
            Console.WriteLine("{0} id'li ürünün stoğundan, {1} adet düşüldü.", urunId, adet);
        }
    }

 

 

Sipariş verme işlemi buradaki tüm business nesnelerini ve doğal olarak model nesnelerini bir arada kullanıyor. İşte bu karmaşık operasyonu, Sipariş Ver butonunun tıklanması çağırırsa bu oldukça işlevsiz bir sonuç doğuracak. O halde bu nesneleri organize eden bir Façade sınıfı yazalım.

 public class SiparisFacade
    {
        private Musteri musteri;
        private KargoSirketi kargoSirketi;
        private UrunIslemleri urunIslemleri = new UrunIslemleri();
        private SiparisIslemleri siparisIslemleri = new SiparisIslemleri();
        private SiparisDetaylari siparisDetaylari = new SiparisDetaylari();


        public void SiparisVer(string musteriAdi, string secilenKargoSirketi, List<SepettekiUrun> urunler)
        {
            musteri = new Musteri { Ad = musteriAdi };
            kargoSirketi = new KargoSirketi { Ad = secilenKargoSirketi };
            int siparisId = siparisIslemleri.SiparisEkle(DateTime.Now, musteri, kargoSirketi);
            siparisDetaylari.SiparisDetaylariniEkle(siparisId, urunler);
            urunler.ForEach(u => urunIslemleri.StokGuncelle(u.Id, u.Adet));
            Console.WriteLine();
            Console.WriteLine("İşlem tamamlandı");


        }

    }

 

 Gördüğünüz gibi Façade sınıfının sadece gerekli metotları dışarıya açık. Yani istemci bu nesneye eriştiğinde, sadece gerekli parametreleri sağlayacak ve işlemi basite indirgemiş olacak. Tıpkı deterjan ve yumuşatıcıyı ayarlayıp makineyi çalıştırmak gibi… Yani örneğin Main metodundan aşağıda gözüktüğü gibi nesnemi çağırabilirim:

class Program
    {
        static void Main(string[] args)
        {
            SiparisFacade siparisFacade = new SiparisFacade();
            List<SepettekiUrun> urunler = new List<SepettekiUrun>
            {
                new SepettekiUrun{ Id=1, UrunAdi="X", Fiyat=5, Adet=2},
                new SepettekiUrun{ Id=2, UrunAdi="Y", Fiyat=8, Adet=3},
                new SepettekiUrun{ Id=1, UrunAdi="Z", Fiyat=10, Adet=1},
                new SepettekiUrun{ Id=1, UrunAdi="Q", Fiyat=20, Adet=1}
            };
            siparisFacade.SiparisVer("Türkay", "Aras Kargo", urunler);
            Console.ReadLine();
        }
    }

Tabii ki çıktıya da göz atalım:


Evet. Kod örneğimizi de tamamladık arkadaşlar. Ancak yazıyı tamamlamadan önce, vurgulanması gereken bir şey var. Façade tasarım deseni, bu haliyle bile birçok farklı teknolojiye ilham vermiş bir desen. Örneğin, bir Web API ya da bir Web Servisi içinde yer alan ve istemci tarafından erişilebilen sınıflar da aynı buradaki SiparisFacade sınıfı gibi, karmaşık işlemleri düzenleyen yapılar değil mi? Yani, öyle altyapılar inşa ediyoruz ki günümüzde; istemciler, yalnızca gerekli metotlara erişip talep-yanıt (request – response) yapısı ile tüm sistemi ayağa kaldırabiliyorlar.

Buradan da görebileceğimiz gibi dostlar, bir probleme geliştirdiğiniz basit ve etkili bir çözüm, aslında başka yönelimlere de ilham olabiliyor. Dolayısıyla bu durum da çözüm odaklı olmanın bir getirisi gibi duyuruyor.

Velhasıl, en sık kullanılan Façade design pattern i böylece sizlere aktarmış oluyorum.

Bir sonraki yazıda görüşmek ümidiyle, hoşça kalın.

1 thought on “Façade Design Pattern

  1. İnternetteki; araba, yemek oluşturma örneklerinden ziyade daha elle tutulur bir şey oldu benim için, ellerinize sağlık.

Leave a Reply