Tasarım Desenleri - Builder

Merhaba Arkadaşlar

Zaman içerisinde geliştirdiğimiz uygulamalar son derece karmaşık bir hal alırlar. Uygulamanın çapının ve ihtiyaçlarının artması bir kenara içerisinde yer alan en küçük parçaların bile kullanımları kompleksleşebilir. Bu küçük birimlerin karmaşıklaşmasına etken olarak gösterilebilecek konulardan biriside, nesne üretimleri için kullanılan sınıfların sayılarının artması ve inşa işlemlerinin kompleks olması olarak düşünülebilir. Hal böyle olunca bazı vakalar için standartlaşmış kalıpları kullanmanın genişleyebilirlik ve ölçeklenebilirlik açısından büyük yararı vardır.

Nesne üretimi söz konusu olduğunda, Creational isimli kategoride yer alan tasarım kalıpları göz önüne alınmaktadır. Bunlardan birisi olan Builder deseni, karmaşık yapıdaki nesnelerin oluşturulmasında, istemcinin sadece nesne tipini belirterek üretimi gerçekleştirebilmesini sağlamak için kullanılmaktadır. 

Bu desende istemcinin kullanmak istediği gerçek ürünün birden fazla sunumunun olabileceği göz önüne alınır. Bu farklı sunumların üretimi ise Builder adı verilen nesnelerin sorumluluğu altındadır. Dolayısıyla Builder kalıbından yararlanılarak aslı ürünün farklı sunumlarının elde edilebilmesi için gerekli olan karmaşık üretim süreçleri, istemciden tamamen soyutlanabilir. Desenin önemli olan özelliklerinden biriside Abstract Factory tasarım kalıbı ile çok benzer yapıda olmasıdır. Ancak arada bazı farklılıklarda vardır. Herşeyden önce Abstract Factory kalıbına göre, fabrikanın metodları kendi nesnelerinin üretiminden doğrudan sorumludur. Builder deseninin başlıca kahramanları aşağıda sıralandığı gibidir.

  • Builder: Product nesnesinin oluşturulması için gerekli soyut arayüzü sunar.
  • ConcreteBuilder: Product nesnesini oluşturur. Product ile ilişkili temel özellikleride tesis eder ve Product' ın elde edilebilmesi için(istemci tarafından) gerekli arayüzü sunar.
  • Director: Builder arayüzünü kullanarak nesne örneklemesini yapar.
  • Product: Üretim sonucu ortaya çıkan nesneyi temsil eder. Dahili yapısı(örneğin temel özellikleri) ConcreteBuilder tarafından inşa edilir.

Bu kahramanlarımızın aralarındaki ilişkileri aşağıdaki diagram üzerindeki dizilimi ise aşağıdaki gibidir.

Builder tasarım kalıbının kullanım oranı doFactory.com sitesinin istatistiklerine göre %40' lar civarındadır. Bunun en büyük nedenlerinden biriside uygun senaryoların tespit edilmesinin zor olmasıdır. Yinede desenin kullanılabileceği bir kaç senaryo üzerinde konuşarak daha kolay anlaşılmasını sağlayabiliriz.

Söz gelimi dofactory.com tarafından verilen örneği göz önüne alalım. Bu örnekte motorsiklet, otomobil, scooter gibi ürünler söz konusudur. Tüm bu araçların istemci açısından kullanılabilir olması için üretim işleminde motorun(her ne kadar motorsiklette ve scooter' da kapı olmasada Embarassed 0 veya null değeri kullanılabilir) , kapıların, viteslerin vb parçalarında üretimi gerekmektedir.

Aslında bu ortak fonksiyonellikler bu ürünlerin hepsi için geçerlidir. Yani bu araçların kendisi bir Product olarak temsil edilebilirler. İstemci, sadece kullanmak istediği ürünün farklı bir sunumunu elde etmek isteyecektir. Bu tip bir senaryoda istemcinin asıl ürüne ulaşmak için ele alması gereken üretim aşamalarından uzaklaştırılarak sadece üretmek istediği ürüne ait tipi bildirmesi yeterli olmalıdır. Bu senaryoda araç(Vehicle) aslında üründür(Product). Motorsiklet veya araba ise araç tipleridir ve üretim işlemleri sonucu ortaya bir Vehicle çıkartırlar. Yani desendeki ConcreteBuilder tipleridir. Bu senaryo pekala bir oyun programı içerisindeki araçların üretimi aşamasında göz önüne alınabilir. 

Diğer bir senaryoda bir firmanın çalışanlarına yılın belirli dönemlerinde farklı tipte promosyon ürünleri gönderdiğini düşünebiliriz. Söz gelimi farklı çalışan profilleri için sunumu farklı olan promosyon ürünlerinin geliştirilmesi safhasındaki üretim karmaşıklığı, Builder deseni ile istemciden uzaklaştırılabilir. Bu senaryoda promosyonun kendisi ürün iken, promosyon ürününü kullanacak olan profil sahipleri ConcreteBuilder tipleri olarak düşünülebilir.

Peki daha gerçekçi bir örnek olamaz mı? Her zaman dediğim gibi, aslında tasarım kalıplarının çoğunun .Net Framework içerisinde kullanıldığını kolaylıkla görebiliriz. Builder tasarım kalıbı için düşünülebilecek en güzel örnek Connection String Builder operasyonudur.

Şekildende görüldüğü gibi bir istemcinin, kullanmak istediği Connection tipi için uygun olan bağlantı bilgisine ihtiyaç vardır. Burada bağlantının string şeklindeki içeriği önemlidir. Bu içeriğin sunum şekli ise OleDb, SQL, ODBC için farklıdır. Dolayısıyla söz konusu farklı string üretimleri için bazı ConcreteBuilder tiplerinden(OleDbConnectionStringBuilder vb...) yararlanılır. Her ne kadar DbConnectionStringBuilder abstract bir sınıf olmasada, Builder tipinin görevini üstlenmektedir.

Ancak benim popüler senaryom şu anda midemden beynime doğru gelen sinyallerinde söylediği üzere Pizzacı örneğidir. Nitekim şu aşamada heleki hafta sonuna girdiğimiz şu güzel Cuma gecesinde, bu deseni eğlenceli bir şekilde ele almamamız için hiç bir sebep bulunmamaktadır. Wink İşte deseni ele aldığımız kod parçaları.

using System;

namespace Builder
{
    // Product class
    public class Pizza
    {
        public string PizzaTipi { get; set; }
        public string Hamur { get; set; }
        public string Sos { get; set; }

        public override string ToString()
        {
            return String.Format("{0} {1} {2}", PizzaTipi, Hamur, Sos);
        }
    }

    // Builder class
    public abstract class PizzaBuilder
    {
        protected Pizza _pizza;

        public Pizza Pizza
        {
            get { return _pizza; }
        }

        public abstract void SosuHazirla();
        public abstract void HamuruHazirla();
    }

    // ConcreteBuilder class
    public class BaharatliPizzaBuilder
        : PizzaBuilder
    {
        public BaharatliPizzaBuilder()
        {
            _pizza = new Pizza { PizzaTipi = "Baharatlı Baharatlı" };
        }
        public override void SosuHazirla()
        {
            _pizza.Sos = "Acı sos, pepperoni, atom biber";
        }

        public override void HamuruHazirla()
        {
            _pizza.Hamur = "İnce Kenar, Kaşarlı";
        }
    }

    // ConcreteBuilder Class
    public class DortMevsimPizzaBuilder
        : PizzaBuilder
    {
        public DortMevsimPizzaBuilder()
        {
            _pizza = new Pizza { PizzaTipi = "4 Mevsim" };
        }
        public override void SosuHazirla()
        {
            _pizza.Sos = "Biber, Domates, Peynir, Salam, Sosis";
        }

        public override void HamuruHazirla()
        {
            _pizza.Hamur = "Kalın, fesleğenli";
        }
    }

    // Director Class
    public class VedenikliKamil
    {
        public void Olustur(PizzaBuilder vBuilder)
        {
            vBuilder.SosuHazirla();
            vBuilder.HamuruHazirla();
        }
    }

    // Client class
    class Program
    {
        static void Main(string[] args)
        {
            PizzaBuilder vBuilder;

            VedenikliKamil kamil= new VedenikliKamil();
            vBuilder = new BaharatliPizzaBuilder();
            
            kamil.Olustur(vBuilder);
            Console.WriteLine(vBuilder.Pizza.ToString());

            vBuilder = new DortMevsimPizzaBuilder();
            kamil.Olustur(vBuilder);
            Console.WriteLine(vBuilder.Pizza.ToString());
        }
    }
}

İstemcinin tek derdi istediği tipte bir pizza almaktır. Örneğin 4 mevsim veya Baharatlı pizza. Bu pizzaların içinde ise soslarının ve hamurlarının belirlenerek üretim işlemine dahil edilmesi gerekmektedir. Bu VenedikliKamil açısından kolay olmakla birlikte istemciyi ilgilendiren bir durum değildir. Bu nedenle istemcinin sadece pizza üretimini gerçekleştiren asıl ConcreteBuilder nesne örneğini seçmesi yeterlidir. Bu seçim işlemi Director sınıfı içerisindeki Olustur metoduna parametre olarak gönderilir. Sonrasında ise istemcinin istediği pizza üretilerek elde edilir. Örneği çalıştırdığımızda aşağıdaki sonuçları elde ederiz.

 

Umarım sizler içinde faydalı bir anlatım olmuştur. Her zamanki gibi bu desenin görsel dersinide en kısa sürede eklemeye çalışacağım. Bu yazının üstünede şöyle güzel bir espresso içilir kanımca Wink 

Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Builder.rar (23,15 kb)

Yorumlar (7) -

  • Hocam tasarim desenlerine devam diyorum Smile
    Elinize saglik yine cok güzel anlatim.
  • Öncelikle Yazılarızı beğenerek takip ediyorum. Gerçekten çok başarılısınız.

    Bir sorum olucaktı bu  Builder Pattern ile ilgili

    bu factory Pattern olmamıs mı. sanki faktory pattern okuyorum zannetim.

    Zaman Ayırdıgınız için Teşekkürler Şimdiden
  • Merhabalar,

    Her iki desende birbirlerine zaman zaman karıştırılmaktadır aslında. Fakat kullanım şekillerini değerlendirirsek şu ayrımları yapabiliriz.

    Builder deseni istemcinin ihtiyaç duyduğu ve üretimi karmaşık olan nesnelerin adım adım oluşturulmasını esas almaktadır. Abstract Factory üretimin karmaşık veya basit olmasına bakmaksızın bir ürün aile grubunu baz alır.

    Builder ürünü son adımda üretmeyi önerirken, Abstract Factory kalıbı ürünün anında üretilip istemciye verilmesine odaklanır.

    Abstract Factory deseninde yer alan fabrikanın metotları fabrikaya ait nesnelerin yaratılmasından sorumludur. Builder deseninde istemci, ürünlerin ne şekilde oluşturulacağına Builder kalıbının metotları ile
    karar verir ve üretilen nesneyi Builder' dan tekrar talep eder.


    Gibi düşünebiliriz. Yazımızdaki genel amaç desenin uygulanış biçimi olduğundan, yukarıdaki ayrımlar babında bakmak sanıyorum ki ayrımı yapmamızı kolaylaştıracaktır.

    Bu güzel soru için teşekkür ederim. İyi çalışmalar.
  • Burak hocam bu nasıl bir anlatım yahu !! canım çok deli pizza pizza çekti Laughing
    emeğine sağlık değerli hocam teşekkürler.
  • Teşekkürler, Burak Hocam, elinize sağlık...
  • #c dili ile yazılmış deseydiniz keşke
    çünkü böyle saçma bir tanımlama java'da yok

    public string PizzaTipi { get; set; }

    çünkü java public değişkene get set oluşturacak kadar tuaf bir dil değil.
    • Oğuzhan Bey merhabalar,

      "Saçmalık, çünkü java public değişkene get set oluşturacak kadar tuaf bir dil değil. " dediniz ve dediğiniz şey bir değişken değil, property. Değişken ile property farklı şeyler. Propertyler field ve methodların birleşimi gibi bir şeydir.  Propertyler, kullanıcı erişmek istediğinde field gibi davranır  fakat fonksiyonel özellikleri devam eder. Get ve Set methodları gibi. Get metodu property içindeki değer okunduğunda çalıştırılır. Set metodu ise property yeni bir değer aldığında işlenir. Üzerinde validasyonlar yapılabiliyor, ORM araçları ile datalar bind edilebiliyor gibi gibi. Java'da her değişken için ayrı ayrı Get ve Set methodlarını oluşturup kod yığını yapmaktansa gayet tatlı bir özellik bu. Bu yapı Vue.js gibi frameworklerde de mevcut (Computed property). Bir şeye yanlış demeden önce doğrusunu da biliyor olmak da gerekir unutmayın lütfen, sadece aradaki farkı söylemek istedim.

      İyi günleriniz olsun..

Yorum ekle

Loading