Composite Pattern
Yapısal tasarım kalıplarımız arasında bulunan composite pattern, hiyerarşik veya konsept olarak tekrarlı ilişkilerin bulunduğu durumlar için kullanabileceğimiz bir tasarım kalıbıdır. Composite tasarım kalıbını diğer yapısal kalıplardan ayıran en belirgin özelliği, bir ebeveyn nesneye birden fazla alt obje bağlanabilmesi ve bunun alt düğümlerde yine aynı şekilde devam edebilmesidir.
Bu kalıp için departmanlar arası gezen bir duyuruyu düşünebiliriz. Yönetim kurulundan bir üye bir kararı insan kaynakları ile paylaşır. İnsan kaynakları kurum kültürüne uygun olarak duyuruyu şekillendirir. Bu hat üzerinde departman direktörleri konuyu kendi alanlarına göre sınıflandırır ve ilgili kısmı paylaşır. Nihayetinde duyuru personele dağılır ve tüm şirkete yayılmış olur. Bu hayali senaryoda duyurumuz bir çok kişinin elinden geçmiştir. Bu kişilerin farklı özellikleri olsa da nihayetinde hepsi personeldir. Ancak her personel kendine özgü bir işlevi yerine getirmektedir. Bu da, teknik olarak, bir sınıfın farklı instancelarını andırmaktadır. Bu durumu kod üzerinde de görelim.
import java.util.List;
import java.util.Objects;
Burada standart bir personel tanımı görülmektedir. Bir personele bağlı başka personeller de olabilir. Bunu da directReports alanında görmekteyiz. Yukarıda bahsettiğimiz, duyurunun her personel tarafından işlenmesi senaryosunun da process() methodunda gerçekleştiğini varsayalım. Dolayısı ile her personel, kendisine bağlı personeller için duyuruyu şekillendirir. Bu durum, kendisine bağlı personel kalmayan kişiye kadar gitmelidir. Böylece process() methodu daha da anlam kazanmaktadır.
Son olarak kodu test etmek için hayali personellerimizi oluşturalım ve tepeden işleyen bir zinciri tetikleyelim.
public class Staff {
private String title;
private List<Staff> directReports;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<Staff> getDirectReports() {
return directReports;
}
public void setDirectReports(List<Staff> directReports) {
this.directReports = directReports;
}
public void process() {
System.out.println(title + " is processing!");
if (!Objects.isNull(directReports)) {
directReports.forEach(staff -> staff.process());
} else {
System.out.println("End of tree");
}
}
}
public class Main {
public static void main(String[] args) {
Staff hrRep = new Staff();
hrRep.setTitle("HR Representative");
Staff manager1 = new Staff();
manager1.setTitle("IT Manager");
Staff manager2 = new Staff();
manager2.setTitle("Operations Manager");
Staff employee1 = new Staff();
employee1.setTitle("IT employee-1");
Staff employee2 = new Staff();
employee2.setTitle("IT employee-2");
Staff employee3 = new Staff();
employee3.setTitle("IT employee-3");
Staff employee4 = new Staff();
employee4.setTitle("Operations employee-4");
Staff employee5 = new Staff();
employee5.setTitle("Operations employee-5");
Staff employee6 = new Staff();
employee6.setTitle("Operations employee-6");
List<Staff> managers = Arrays.asList(new Staff[]{manager1, manager2});
List<Staff> itEmployees = Arrays.asList(new Staff[]{employee1, employee2, employee3});
List<Staff> operationsEmployees = Arrays.asList(new Staff[]{employee4, employee5, employee6});
hrRep.setDirectReports(managers);
manager1.setDirectReports(itEmployees);
manager2.setDirectReports(operationsEmployees);
hrRep.process();
}
}
Çıktı:
HR Representative is processing!
IT Manager is processing!
IT employee-1 is processing!
End of tree
IT employee-2 is processing!
End of tree
IT employee-3 is processing!
End of tree
Operations Manager is processing!
Operations employee-4 is processing!
End of tree
Operations employee-5 is processing!
End of tree
Operations employee-6 is processing!
End of tree
Kodun son kısmını manager1 nesnesi üzerinden tetikleseydik, hiyerarşiye istinaden daha farklı bir çıktı elde ederdik.
manager1.process();
Çıktı:
IT Manager is processing!
IT employee-1 is processing!
End of tree
IT employee-2 is processing!
End of tree
IT employee-3 is processing!
End of tree
Son olarak bir employee nesnesi üzerinden kodu tetikleyip çıktısına bakalım.
employee1.process();
Çıktı:
IT employee-1 is processing!
End of tree
Composite pattern ağaç tarzı yapılarda çok işimize yarayan bir tasarım kalıbıdır. Özellikle özyinelemeli (recursive) işlemlerde karşımıza çıkan yapıların oluşturulması ve yönetimi esnasında kullanılır. Open/closed prensibine hizmet eder. Ana hedefi yapımızı tekil bir interface/sınıf arkasına almak üzerine kuruludur. Bu da aynı zamanda genel bir arayüz/sınıf üretmenin sorun olabileceği anlamına gelir. Zira oluşabilecek farklı durumların varlığı, karmaşanın da olasılığını yükseltmektedir. Buna karşın, kalıbın doğası gereği durumu genelleştirmemiz gerekecektir.