Bir şirkette aşağıdaki hiyerarşide personel pozisyonları bulunmaktadır.
Proje Yöneticisi
Takım Lideri
Yazılım Geliştirici
Her bir pozisyonda bulunan personel, hiyerarşik olarak kendisinden sonra gelen herhangi bir pozisyondaki personeli maiyetinde barındırabilmektedir.
Bu senaryoda herhangi bir pozisyondaki personelin, maiyetindeki personellerin bilgilerini ve toplam maaşlarını hesaplayıp karşılığına yazdıralım.
ÇÖZÜM
Adım 1(Component Soyut Sınıfının Tasarlanması)
Composite pattern’ın tasarımında ilk olarak Leaf ve Composite nesnelerimizin ortak arayüzü olan Component abstract class’ı tasarlanarak başlanmaktadır. Haliyle bizler de vakit kaybetmeksizin ilk olarak ilgili sınıfı oluşturarak başlıyoruz.
//Component
public abstract class Employee
{
protected string _name;
protected double _salary;
protected Employee(string name, double salary)
{
_name = name;
_salary = salary;
}
public string GetName()
=> _name;
public double GetSalary()
=> _salary;
public abstract void Print();
}
Yukarıdaki ‘Employee’ adıyla tasarlanan Component sınıfı direkt Leaf ve Composite nesnelerinin kullanabileceği şekilde ortak member’larla tasarlanmıştır. Sadece Composite nesnelerine özel fonksiyonları barındıran Component tasarımı ise aşağıdaki olacaktır. Böylece hem Leaf nesnelerinde anlamsız member’lar olmayacak hem de arayüz ayrım prensibini sağlamış bulunacağız.
Ayrıca yukarıdaki Component örneğinde ‘GetName’ ve ‘GetSalary’ metotlarının gövdeleri direkt oluşturulmuşken, ‘Print’ metodunun gövdesi concrete olacak olan Composite ve Leaf nesnelerine bırakılmıştır. Nihayetinde bu kod, buradaki davranışın ihtiyaca göre tarafımızca belirlendiğine bir örnektir. Misal bizim concrete nesnelerde maaşlarla ilgili ekstradan işlemler yapmamız gerekseydi ‘GetSalary’ metodu abstract olarak ayarlayıp, bu işi ilgili nesnesinde inşaya bırakabilirdik. Ama gerekmediği için kıssadan hisse yapıp gerekli işlemi burada gerçekleştirmekteyiz.
//Component
public abstract class EmployeeComposite : Employee
{
protected List<Employee> _employees = new();
protected EmployeeComposite(string name, double salary) : base(name, salary)
{
}
public void AddEmployee(Employee employee)
=> _employees.Add(employee);
public void RemoveEmployee(Employee employee)
=> _employees.Remove(employee);
}
Composite nesneleri için özel olan fonksiyonları barındıran Component soyut sınıfımızda yukarıdaki gibi olacaktır. Burada da ‘AddEmployee’ ve ‘RemoveEmployee’ metotlarının gövdelerini aynı mantıkla concrete olan Composite nesnelerine bırakmaksızın direkt olarak inşa etmiş bulunmaktayız. Haliyle ilgili metotlar sadece ekleme ve çıkarma işlemleri yapacaklarından ve ekstra bir iş yürütmeyeceklerinden dolayı direkt bu ihtiyacı burada karşılamış bulunmaktayız.
Adım 2(Composite Sınıfının Tasarlanması)
Şimdi sıra, senaryo gereği altında en az bir pozisyondan personel barındıracak olan Composite sınıfını tasarlamaya gelmiş bulunmaktadır.
//Component
public class Manager : EmployeeComposite
{
public Manager(string name, double salary) : base(name, salary)
{
}
public override void Print()
{
Console.WriteLine($"Name\t\t:{GetName()}");
Console.WriteLine($"Salary\t\t:{GetSalary()}");
double totalSalary = 0;
_employees.ForEach(employee =>
{
totalSalary += employee.GetSalary();
employee.Print();
});
Console.WriteLine($"Total Salary\t:{totalSalary}");
}
}
Yukarıdaki ‘Manager’ isimli Component sınıfına göz atarsanız eğer ‘Print’ fonksiyonu ile ilgili personelin adını ve maaşını ekrana yazdırmakla birlikte altındaki elemanların da(ki bu elemanlar normal personel olabileceği gibi yönetici pozisyonunda bir personel de olabilir) toplam maaşını hesaplamakta ve ‘Print’ fonksiyonlarını tetikleyerek onlara dair bilgileri ekrana yazdırmaktadır.
Adım 3(Leaf Sınıfının Tasarlanması)
Şimdi ise altında herhangi bir pozisyondan personel barındırmayan personelleri temsil edecek olan Leaf sınıfını tasarlamaya sıra gelmiştir.
//Leaf
public class SoftwareDeveloper : Employee
{
public SoftwareDeveloper(string name, double salary) : base(name, salary)
{
}
public override void Print()
{
Console.WriteLine($"\tName\t\t:{GetName()}");
Console.WriteLine($"\tSalary\t\t:{GetSalary()}");
}
}
Yukarıdaki ‘SoftwareDeveloper’ isimli Leaf nesnesinde ise ‘Print’ fonksiyonuyla sadece ilgili personele dair adı ve maaş bilgileri ekrana yazdırılmaktadır.
Adım 4(Test)
Bu ana kadar dikkat ederseniz; ‘Proje Yöneticisi’ ve ‘Takım Lideri’ pozisyonları ‘Manager’ sınıfıyla, ‘Yazılım Geliştirici’ pozisyonu ise ‘SoftwareDeveloper’ sınıfıyla temsil edilmektedir. Artık yapılan bu tasarımı rahatlıkla test edebiliriz.
Yukarıdaki örnek kodu derleyip, çalıştırdığımızda aşağıdaki çıktıyı verecektir.
Görüldüğü üzere tüm pozisyonlardaki personellerin ve maiyetlerindeki diğer personellerin toplam maaşla birlikte bilgileri yazdırılmış bulunmaktadır.
Bir insanın yardım etme hissiyatı, diğerinin acizliği ya da ezikliğinden değildir. Bilakis onu kendinden çok insan sıfatıyla görmesindendir. Çünkü, insana hizmet etmek insana yakışır.
Bu alanda veya başka bir alanda, benim ve diğer yardımcı insanların paylaşımlarına lütfen acizliğiniz ve ezikliğinizle yaklaşmayınız. İzin istemek, benim hükmüm altına girmeniz anlamına gelmemektedir.