Builder Design Pattern
Bu tasarım desenini örnek bir senaryo üzerinden anlatmaya başlayalım.
Çalıştığınız projede ürün sepeti için sizden bir pojo oluşturmanızı istediler.Siz de Builder tasarım deseninden bihaber aşağıda ki örnekte olduğu gibi pojonunuzu oluşturup propertylerinizi yazdınız getter ve setleri da ekledikten sonra ihtiyaç duyduğunuz parametreleri constructora eklediniz. Ben örnek olsun diye bütün propertyleri ekledim.
Sonra classı kullanacağınız yerler için 10 belki 20 yerde ProductBasket classını yarattınız. Gerekli işlemleri yaptınız ve konu kapandı. Her şey buraya kadar çok, güzel bir problem yok. Geliştirmenizi bitirdiniz ve mutlusunuz. Fakat iki gün sonra classınıza bir property daha eklemeniz gerekti. Hayda işler değişti; yeni propertynizi entity’e eklediniz ve constructora parametre olarak da eklemeniz gerekiyor. Constructor değiştirip yeni bir parametre daha eklediniz. Fakat bu sefer classı yaratığınız her yer kırmızı vermeye başladı.Aşağıdaki fotoğrafta gösterildiği gibi yaratığımız instance yeni bir parametre vermemizi istiyor.Bu işlemin bir sürü yerde yapıldığını düşünelim.
Aşağıdaki fotoğrafta verdiği hata gibi 5. parametre değerini de girmemizi istiyor.
Teker teker classı yarattığınız yerde yeni bir parametre daha verip (muhtemelen null değeri:)) sonra yeni geliştirmeniz için tekrar metodlar içinde ProductBasket adında yeni yeni instanceler yarattınız.Gerekli işlemleri yaptınız.Zor da olsa geliştirmenizi bitirdiniz.Tam rahatladınız derken hop yeni bir geliştirme, yine entitye yeni bir property ihtiyacı daha doğdu.Hele ki başta mimarisi kötü tasarlanmış bir projede çalışıyorsanız ve sürekli geliştirmenizi yeni propertyler eklemeden ilerletemiyorsanız işiniz yaş; her seferinde bir sürü değişiklik.Constructor eklediğiniz yeni parametre için classı kullandığınız her yer de gidip değiştirmeniz gerekecektir.Büyük bir iş yükü.
Ama bir dakika aklınıza daha pratik bir yöntem geldi.Yeni constructur yaratmaya karar verdiniz.Aşağıda görüldüğü gibi artık iki constructor var.
Şimdilik işiniz görüldü. Eliniz de başka parametreli bir constrctuar var süper artık rahatım derken tekrar tekrar aynı ihtiyaçlar, yeni geliştirmeler ve her seferinde gidip bir yerleri düzeltmek yerine yeni constracuarlar yarattınız. Bir süre sonra her entitynizde onlarca farklı parametreli consturactuar kombinasyonu oluştu. Biz bunu bir class üzerinden konuşuyoruz fakat bunu onlarca class için yaptığımızı düşürsek projede inanılmaz bir karmaşa ve kod kalabalığı var.Artık her instance yaratmak nerdeyse bi işkence haline geldi. En ufak geliştirme inanılmaz kod kalabalığı oluşturdu. Karmaşık yönetmesi zor kod kalabalıgı ama neyse zaten sıkıldınız artık, belki yakında projenizi bile değiştirisiniz. Vee Nihayet projenizi değişirdiniz artık rahatsınız. Tam kurtuldum derken bildiğiniz ama unuttugunuz bir özellik “Annotate” özelliği.Siz projeden çıktıktan sonra yerinize gelen yazılımcı kodları inceledi işin içerisinden çıkalmayacak bir halde nerdeyse kod satırlarını annotate özelliğinde kodu yazan kişinin adı soyadı kabak gibi ortada :) artık yerinize gelen yazılımcı sizin yazdığınız kodlar üzerinde bir geliştirme yapmak istediğinde kulağınızda ufak bir çınlama hissedebilirsiniz:)
Şimdi bu senaryonun projemiz de bıraktığı ve bırakacağı bilançoları maddeler halinde anlatalım.
- Nesneyi yarattığımız zaman ki zorunlu parametrelerin komplex bir hal aldığını görürüz.Parametrelerin çoğunda null değerini vermek zorunda kalırız
- Elimizde çok fazla constructor kombinasyonu oluştu gereksiz bir kod kalabalığı var.Zorunlu bir property başka bir consturacturda zorunlu değil.
- Yeni bir geliştirme geldiğinde yapacağımız iş çok basit bile olsa çok fazla yerde değişiklik yapmak zorunda kalırız.
- Kodun anlaşılabilirliğini ve yönetimini zorlaştırırız.
- Bir nesne yarattık diyelim.Elimizde çok fazla constructor var.Bunlardan herhangi birini kullabiliriz. Yani zorunlu bir alan olan bir constructor başka bir constructor zorunlu alan olmayabilir.Mesela başka bir yazılımcı geldi yeni bir constructor daha oluşturdu dışardan kodunuza müdahele edebildi ve siz bunu fark etmeyebilirsiniz.Bir örnek verelim..
Yukarıda ürün sepeti diye bir class oluşturduk.Bu alanda hediye paketi yani giftPack alanın nesneyi yarattığımızda zorunlu olması gerekiyor. Çünkü müşteri ya hediye paketi seçeneğine tıklar veyahut tıklamaz.Nesneyi yarattığımızda elimizde true veya false bilgisinin kesin olması gerekiyor.Kargo entegrasyonu tarafında çalışan yazılımcı ProductBasket nesnesini yaratıp işine yarayan bilgileri setledi fakat nesneyi yaratırken giftPack parametresi artık zorunlu bir alan olmadığı için bu bilgiyi setlemedi veya unuttu kodda da bir hata oluşmayacağından dolayı habersiz bir şekilde bu bilgiyi entegrasyonu yaptığı dış sisteme yani anlaşmalı olduğu kargo firmasına gönderdi ve onların ekranlarını tetikledi.Kargo firması bu bilgiyi aldı fakat hediye paketi seçeneği olmadığı için hediye paketi yapmadan gönderdi.Oysa ki müşteri hediye paketi seçeneğini tıklamıştı.Büyük bir problem değil mi ?
Yukarda anlattığım senaryolar Builder design pattern kullanmayan bir yazılımcının yaşayacağı çok muhtemelen bir olayıdır. Aslında yazıyı daha çok teknik bilgilerle yazıp neyin nasıl oldugunı açık bir şekilde anlatmaya hazırlanmıştım.Fakat özellikle tasarım desenlerini anlamaya çalırken onun yokluğunda karşılışacağımız uzun vadeli problemleri anlatmak daha anlaşılır olacagını düşündüm.
Çünkü genel olarak yazılım tasarım desenleri uzun vadede projeyi korumaya, karmaşık kod kalabalıgını önlemeye, kodun yönetilebilirliğini amaçlar. Sadece sizi değil sizden sonra gelen yazılımcının
projeye olabiliğince hızlı anlamasını amaçlar.
Bu Builder design patternin yokluğunda karşılacagımız problemleri anladığımıza göre, şimdi buna nasıl bir çözüm getirlidiğini ve olayın ne kadar basit ve anlaşılır olduğunu incelemeye başalyabiliriz.
Aşağıda oluşturduğum classı inceleyelim.
Yukardaki kodu inceleyelim:Önce statik ProudctBuilder classı ekledik ardından propertylerimizi..
Her propertynin metodunu oluşturup return tipini de ProudctBuilder olarak belirledikten sonra satır 31–33 arasında yaptığmız gibi build adında bir metod yaratıp return new ProductBasket1(this); yaptık.
Satır 35–40 arasında zorunlu propertyleri parametre olarak verip ProductBasket1Builder classını satır 11 de ki constructora parametre olarak verdik. Aşağıdaki fotoğraf ile bunun nasıl çağırıldığına bakalım.
Builder patternin kullanımı da bu şekilde fakat son olarak şunu söylemek istiyorum. 1. instanceyi yaratırken satır 7 de classımızı yarattık 9. satır da optional alan olan prodcuType setledik.Farz edelim program çalıştığında 9. satır da bir problem ile karşılaşıldı ve hata fırlattı 7. satırda ki yarattığımız class boşuna yaratılmış oldu.
Ama işlemleri 14. satırda yaptığımız gibi yaparsak propertyler setlenmeden nesne yaratılmayacağı için bir hata ile karşılaşıldığında boşuna instance yaratılmayacaktır.Bu da programın performansı açından önemlidir.
Builder pattern hakkında söyleyeceklerim şimdilik bu kadar yakın zamanda Lombok dependency hakkında ufak bir yazı ekleyip Builder desingin daha kolay bir yöntemini anlatacağım.