Selamlar! E-bergi'nin Mayıs sayısı için bir tasarım desenini daha incelemeye aldım. Umarım beğenirsiniz.
Tasarımınızın ilerleyen aşamalarında, birbirleriyle sürekli iletişim halinde olması gereken alt modüllerle uğraşmak durumunda kalırsınız. En çok rastlanan durumlardan bir tanesi de, belli işlevleri birbirinden ayrışmaz derecede ilgili, birisini yeniden kullanırken öbürkünü de yeniden kullanmanızı gerektiren ama farklı altsistemlerde bulunan sınıfların tasarımda yarattığı sıkıntıdır.
Böyle bir durumdaki iki sınıfın arasındaki bağlantı seviyesini nasıl azaltabiliriz, ve böylece daha esnek bir sistem elde ederiz? İşte bu noktada “Gözlemci Deseni” işimize yaramaya başlıyor. “Gözlemci Deseni”, iki temel bileşenden oluşmaktadır: “_Gözlemci_” ve “_Gözlenen_”.
Java'nın kütüphanesinde Observerarayüzü ve Observable sınıfı, ve diğer ilgili çocuk-sınıflar tanımlanmış durumda, ama kendimiz de tanımlayabiliriz. Desenin UML şeması şuna benziyor:
“_Gözlenen_”in aynı zamanda pek çok “_Gözlemci_”si olabilir ve gözlemcilerine teker teker haber yollayabilir. Aynı şekilde, “_Gözlemci_” birden fazla “_Gözlenen_”i gözlemleyebilir ve gözlemlediği nesnelerden aldığı bilgileri ayrı ayrı işleyebilir durumda olmalıdır.
“Gözlemci Deseni”ni pek çok farklı tip uygulamada ( istatistik, hava durumu, bilgisayar ağları modelleme, vs. ) kullanabilirsiniz. Özellikle kullanıcı arayüzü bileşenleriyle tanım kümesi bileşenleri arasındaki iletişimde buna benzer bir yaklaşım sergilemek isteyebilirsiniz. “_Gozlenen_” arayüzünüzü daha da özelleştirmeyi düşünebilirsiniz. Örneğin, “_HavaDurumuGozlenen_” diye bir arayüz tasarlayabilir ve “_Gozlenen_” arayüzünün gerektirdiği işlevlere ek olarak başka işlevler de belirleyebilirsiniz. Ardından, bu arayüzünüzü ilgili sınıfa (örn: Meteoroloji) uygulattırabilirsiniz.
Meteoroloji ve HaberMerkezi sınıfları arasında bir “Gözlemci Deseni” uygularsak, şuna benzer kodlar oluşturmamız gerekecektir:
public class Meteoroloji implements HavaDurumuGozlenen
{
ArrayList gozlemciler;
ArrayList sehirler;
String merkezAdi;
public void gozlemciEkle(Gozlemci g)
{
gozlemciler.add(g);
}
// Her önemli değişiklikte bu metodu çağır.
private void gozlemcilere Bildir(Sehir s)
{
HavaDegisikligi degisiklik = new HavaDegisikligi(s, this.merkezAdi);
for(int observerCount = 0; observerCount < gozlemciler.size(); observerCount ++)
{
gozlemciler.get(observerCount).notAl(degisiklik);
}
}
public void sicaklikOlcumu(Sehir s)
{
// s Şehrinden alınan hava bilgileri işlenir,...
s.setSicaklik(yeniSicaklik);
s.setHavaDurumu(havaDurumu);
// ardından...
gozlemcilereBildir(s);
}
}
/*Değiştirilen ve aktarılan bilgi: Şehir*/
public class Sehir
{
String sehirAdi;
int sicaklik;
String havaDurumu;
// Diğer önemli fonksiyonlar...
public Sehir(...) {...}
public String getSehirAdi() {...}
public void setSehirAdi(String sehirAdi) {...}
public int getSicaklik() {...}
public void setSicaklik(int yeniSicaklik) {...}
public String getHavaDurumu() {...}
public void setHavaDurumu(String yeniHavaDurumu) {...}
}
/* Meteorolojiden gelen değişiklikleri HavaDegisikligi ile aktaralım...*/
public class HavaDegisikligi
{
Sehir degismisSehir;
// vesaire vesaire
}
/* Meteoroloji'den gelen bilgileri HaberMerkezi gözlemlesin...*/
public class HaberMerkezi extends Gozlemci
{
public void notAl(HavaDegisikligi havaDegisikligi)
{
// değiştirilmiş şehirleri bul, gerekli aktarmaları yap
}
public void notAl(AjansHaberi sonDakikaHaberi)
{
// burada da Ajanslardan alınan bilgilerde aktrama yapılsın.
}
public void havaDurumuGoruntule()
{
// Şehirlerin hava durumu bilgilerini görüntüle.
}
}
Peki bu tasarım deseni, verimli tasarım ilkelerine ne kadar uyuyor?
Low Coupling: “_Gözleyen_”, “_Gözlenen_”in bilgilerini değiştirmek gibi fazladan bir sorumluluğa sahip değildir ve onunla bağlantılı olan diğer bileşenlerle bağlantıya geçmek durumunda değildir. Böylece bu iki sınıfın bağlantılı olduğu diğer bileşenler değişse bile aralarındaki işlevsellik bir sorun yaşamadan sürdürülebilir.
High Cohesion: “_Gözlemci_”, “_Gözlenen_”in bilgilerini değiştirmek gibi fazladan bir sorumluluğa sahip değildir. “_Gözlenen_”in de bu desendeki tek sorumluluğu, kendindeki değişiklikleri “_Gözlemci_”e bildirmektir. “_Gözlemci_”in bu durumda ne yapması gerektiğiyle ilgi ayrıntılarla uğraşmaz.
Karşı-Desenler:
- Gözlenen sınıfını Gözlemci sınıfının atası olarak tasarlamayın! Gözlemci kendi kendini gözlemler duruma düşmemeli!
- Gözlenen ve Gözlemci örneklemeleri arasında bağlantı kurmayın! Aradaki tek köprü güncelleme/notalma fonksiyonu olsun. Her iki sınıf da kendi işini kendisi halletsin.
Bir sonraki yazıda görüşmek üzere, her şey gönlünüzce olsun...