Design Pattern 1 – Builder
/*
Yazı serisine birden girmemin bir nedeni vardır. İlerleyen bölümlerde Tasarım desenleri nedir, ne iş yapar, nerelerde kullanılır ve neden ihtiyaç duyulmuştur’u örneklerle anlatacağım bir 4’lük olacaktır. Bilgilerinize.
*/
Herkese Merhaba,
Bu serimizde inşAllah her hafta bir tasarım deseni ve onunla ilgili bilgiler paylaşacağız.
Bu haftaki ilk tasarım desenimiz Builder tasarım deseni. Haydi başlayalım.
Builder, nesne üretim sürecinde değişik parçalar birleştirilip istenilen tipte nesne oluşumunu amaçlamaktadır. eee Yani ? diyorsunuz değil mi ?
Bazen bir nesneyi yaratmak, basit bir yapılandırıcı çağrısından ziyade bir süreç içinde olur.Böyle durumlarda hem nesne karmaşıktır hem de nesneyi yaratma süreci karmaşıktır.Bu türden nesneleri oluşturmak için gerekli süreç Builder kalıbı olarak modellenebilir.
Bir nesnenin karmaşık olduğunun en temel göstergesi, çok parametre alan kurucularıdır (constructor). Kurucuyageçilen parametrelerin de oluşturulması gerektiği düşünüldüğünde bu sürecin soyutlanması gerektiği açık hale gelir.Factory Method ve Abstract Factory bu problemi çözmez. Çünkü J. Bloch’un da Effective Java kitabında söylediği gibi bu iki kalıp’ta kurucular gibi büyüme (scale) probemi olan yapılardır.
Builder Design aslında bir oluşturucu (creational) tasarım kalıbıdır.
Amacı çok fazla sayıda constructor’ın yerine daha performanslı olarak kullanılmasıdır.
Öncelikle soruna odaklanalım. Nedir bu sorun ?
Kod üzerinde anlatmak gerekirse.
Lab lab= new Lab();
Lab lab2 = new Lab("Fırat Üniversitesi","Bilgisayar Mühendisliği", "LABADI",1, 24, true,"Ümit KÖSE"
,"umiitkose@gmail.com");
Örnek Kod :
public class Lab {
private String labUniversiteIsmi;
private String labUniversiteBolumu;
private String labIsmi;
private int labSayisi;
private int labKontejyani;
private boolean labKullanilabilirMi;
private String labSorumlusu;
public Lab(String labUniversiteIsmi, String labUniversiteBolumu, String labIsmi, int labSayisi, int labKontejyani, boolean labKullanilabilirMi, String labSorumlusu) {
this.labUniversiteIsmi = labUniversiteIsmi;
this.labUniversiteBolumu = labUniversiteBolumu;
this.labIsmi = labIsmi;
this.labSayisi = labSayisi;
this.labKontejyani = labKontejyani;
this.labKullanilabilirMi = labKullanilabilirMi;
this.labSorumlusu = labSorumlusu;
}
public Lab(String labUniversiteIsmi, String labUniversiteBolumu, String labIsmi) {
this.labUniversiteIsmi = labUniversiteIsmi;
this.labUniversiteBolumu = labUniversiteBolumu;
this.labIsmi = labIsmi;
}
/*
...
*/
}
Mesela yukarda Lab sınıfından 2 farklı constructor’a sahip nesne oluşturduk. Hadi bide baktık ki örneğin sallıyorum bu constructorda farklı bir parametre’ye daha ihtiyaç duyduk. Tekrar Lab sınıfında yeniden constructor yazdık. Her zaman bu yöntem iyi değildir neden mi ?
Şimdi sorunları sıralıyım.
- Constructor’ın hangi parametresi hangi tip’i alıyor, hangi sırada bilmiyoruz ve yönetmesi zor oluyor.
- Birden fazla constructor kod kalitesini düşürüyor. Kodun okunmasını zorlaştırıyor.
- Bizi ya tek constructor’da tüm parametreleri kullanmaya zorluyor ya da yeni constructorlar yazmaya.
Peki bu sorunu nasıl çözeceğiz ? İşte burada builder yapısı devreye giriyor.
package builderdesignexample1;
/**
*
* @author umiitkose
*/public class Lab {
private final String labUniversiteIsmi;
private final String labUniversiteBolumu;
private final String labIsmi;
private final int labSayisi;
private final int labKontejyani;
private final boolean labKullanilabilirMi;
private final String labSorumlusu;
public Lab(LabBuilder labBuilder) {
this.labUniversiteIsmi = labBuilder.labUniversiteIsmi;
this.labUniversiteBolumu = labBuilder.labUniversiteBolumu;
this.labIsmi = labBuilder.labIsmi;
this.labSayisi = labBuilder.labSayisi;
this.labKontejyani = labBuilder.labKontejyani;
this.labKullanilabilirMi = labBuilder.labKullanilabilirMi;
this.labSorumlusu = labBuilder.labSorumlusu;
}
public String getLabUniversiteIsmi() {
return labUniversiteIsmi;
}
public String getLabUniversiteBolumu() {
return labUniversiteBolumu;
}
public String getLabIsmi() {
return labIsmi;
}
public int getLabSayisi() {
return labSayisi;
}
public int getLabKontejyani() {
return labKontejyani;
}
public boolean isLabKullanilabilirMi() {
return labKullanilabilirMi;
}
public String getLabSorumlusu() {
return labSorumlusu;
}
@Override
public String toString() {
return "Lab{" + "labUniversiteIsmi=" + labUniversiteIsmi + ", labUniversiteBolumu=" + labUniversiteBolumu + ", labIsmi=" + labIsmi + ", labSayisi=" + labSayisi + ", labKontejyani=" + labKontejyani + ", labKullanilabilirMi=" + labKullanilabilirMi + ", labSorumlusu=" + labSorumlusu + '}';
}
public static class LabBuilder{
private final String labUniversiteIsmi;
private final String labUniversiteBolumu;
private final String labIsmi;
private int labSayisi;
private int labKontejyani;
private boolean labKullanilabilirMi;
private String labSorumlusu;
public LabBuilder(String labUniversiteIsmi, String labUniversiteBolumu, String labIsmi) {
this.labUniversiteIsmi = labUniversiteIsmi;
this.labUniversiteBolumu = labUniversiteBolumu;
this.labIsmi = labIsmi;
}
public LabBuilder labSayisi(int labSayisi){
this.labSayisi=labSayisi;
return this;
}
public LabBuilder labKontejyani(int labKontejyani){
this.labKontejyani=labKontejyani;
return this;
}
public LabBuilder labKullanilabilirMi(boolean labKullanilabilirMi){
this.labKullanilabilirMi=labKullanilabilirMi;
return this;
}
public LabBuilder labSorumlusu(String labSorumlusu){
this.labSorumlusu=labSorumlusu;
return this;
}
public Lab build(){
Lab lab=new Lab(this);
return lab;
}
}
} public static void main(String[] args) {
Lab bilMuh=new Lab.LabBuilder("Fırat Üniversitesi", "Bilgisayar Mühendisliği","Fethi SEKİN Lab").build();
System.out.println(bilMuh);
Lab kimyaLab=new Lab.LabBuilder("Niğde Ömer HALİSDEMİR Üniversitesi", "Kimya Mühendisliği","Ömer HALİSDEMİR Lab").labKontejyani(23).labKullanilabilirMi(true).build();
System.out.println(kimyaLab);
}
Şimdi Gelelim kodumuzu anlatmaya,
Lab sınıfını incelediğimizde şunlarla karşılaşacağız:
- Final değişken javada içerisine zorunlu bir değişken ataması olan ve değişkenin değerinin değiştirilmediği bir keyword’tur. Sınıf içerisinde dikkat ettiniz mi final değişkenleri bulunmakta. Hem değişmeyecek olması hemde değer alması ile biz LabBuilder’da zorunlu olmasını istediğimiz alanları belirleyebilir, hemde bunu Lab nesnesinde rahatlıkla kullanabilmekteyiz.
- Lab sınıfında sadece get işlemlerimizi yapıyoruz. Set işlemleri ise LabBuilder içinde.
- LabBuilder’ın Constructor’ı 3 parametreyi alıyor ve bunu Lab nesnesine zorunlu kılıyor. Yani Biz Lab nesnesi oluştururken LabBuilder’daki 3 değişkeni zorunlu olarak kullanacağız.
Projeye erişmek için:
//github.com/umiitkose/DesignPattern/tree/master/BuilderDesign
Kaynakça :
//sourcemaking.com/design_patterns/builder/java/2
//www.tutorialspoint.com/design_pattern/builder_pattern.htm
//blog.asosyalbebe.com/2017/05/builder-pattern-temiz-kod-yazmak.html –> Bence bu konuda en detaylı kaynak. Ellerinize sağlık
//blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/ –> Örneği Çok İyidir.
//www.journaldev.com/1425/builder-design-pattern-in-java
//ilkaygunel.com/blog/2017/builder-design-pattern-in-java/
//sourcemaking.com/design_patterns/builder/java/2
Geniş çaplı kaynakça ve araştırma için:
//www.utdallas.edu/~chung/SP/applying-uml-and-patterns.pdf
Head First Design Pattern –> Kitap




