Java Kodunuzun Nesne-Merkezli Olmadığının 10 İşareti – IX: Demeter prensibini ihlal eden metotlar.

Geliştirdiğimiz Java kodunun nesne-merkezli olmadığının 10 işaretinin neler olduğunu bu yazıda listelemiş ve ilk yedi maddeyi daha önce ele almıştık. Şimdi de sekizinci maddeyi inceleyelim:

Demeter prensibini ihlal eden metotlara. (Methods that break the Demeter law.)

Demeter prensibi, bir nesnenin metotlarının, hangi nesnelerin metotlarını çağırabileceğini belirler. Buna göre bir nesnenin metotlarında, kendisi üzerinde metot çağrısı yapabileceği nesneler ancak şunlar olabilir:

  • kendisi,
  • nesne değişkenleri,
  • metoda geçilen parametre nesneler,
  • metotta oluşturulan nesneler.

Yani bir nesne ancak arkadaşlarıyla konuşur, yabancılarla konuşmaz.

Bu durumu bir örnekle açıklayalım: 

public class A{
   private B b;
	
   public void f(C c){
      h();                      // 0- Yapılabilir    
      b.g();		    	// 1- Yapılabilir
      c.u();		    	// 2- Yapılabilir
      D d = new D()
      d.v();		    	// 3- Yapılabilir
      E e = c.w();      
      e.z();	  //4- Yapma bunu! E’den iş isteme, C’den,                       //E'den iş istemesini talep et.
   }

   public void h(){
      ...
   }
}

 

Bir nesnenin metotdunda, o nesnenin diğer metotlarını çağırmak son derece tabidir. “0”de ifade edilen durum budur.

Demeter kuralına göre, bir nesnenin bir metodunda, o nesnenin değişkenlerinden olan nesneler üzerinde metot çağrısı yapabilirsiniz. “1”de ifade edilen durum budur. Bu normaldir çünkü, nesne değişkenleri, nesnenin parçalarıdır, beraber yaşadığı nesnelerdir.

“2”de ifade edilen satırda çağrılan “u()” metodu “f()” metoduna geçilen bir parametre olan “c” nesnesi üzerindeki bir metottur. Bu durum da normaldir çünkü, “c” nesnesi “f()” metoduna zaten işlenmek üzere argüman olarak geçilmektedir.

“3”de ifade edilen satırda çağrılan “v()” metodu da “f” metodunda oluşturulan D tipindeki bir “d” nesnesi üzerindeki bir metottur. Bu durum da normaldir çünkü, “d” nesnesi “f” metodunda zaten ihtiyaç olarak oluşturulmaktadır.

“4”deki durum ise yukarıdaki üç halden farklıdır çünkü bu satırda üzerinde metot çağrısı yapılan “E” tipindeki “e” nesnesi, “A” sınıfının nesnelerinin doğrudan bildiği bir nesne değildir.

Demeter kuralı, bize bir nesnesin sahip olabileceği bağımlılıklarla ilgili bilgi verir, olabildiğince az bağımlılık yaratarak programlama yapmamızı sağlar. Nesne, tabi olarak bildiği nesneler dışında kimseyle konuşmamalıdır, sdece ve sadece yakınında olan nesneleri bilmelidir. Bu yüzden bu prensibe “principle of least information” da denir, yani “en az bilgi prensibi”. Nesneler olabildğince az bilgi bilmelidirler. Nesneler sadece en yakınındaki nesneleri bilmelidirler. Bu durumu şöyle bir örnekle de açıklayabiliriz:

Bir şirkette müdür, müdürün sekreteri ve fotokopici olsun. Müdür bazı belgelerin fotokopisine ihtiyaç duyduğunda yapacağı şey, sekreterinden fotokopiciye gidip o belgelerin fotokopisini çektirmesini istemektir. Bu durumdaki haberleşme şekli makul olandır ve aşağıda gösterilmiştir:

Demeter1

Bir de şu durumu düşünün: Müdür sekreterden bunu istemek yerine, sekretere, “bana fotokopiciyi cağırır mısın” diye istekte bulunsa, müdür aslında konuşmaması gereken bir nesneye ulaşmış olacak ve konuşµa hiyerarşisi bozulacaktır. Bu durumu şöyle resmedebiliriz:

Demeter2

Demeter kuralına uymak, paketler, modüller, bileşenler ve katmanlar arasındaki haberleşmeyi düzenler. Demeter kuralına uymadığımızda bağımlılığı (coupling) yüksek yapılara sebep oluruz. Bu durumda da yazılımlarımızın bakımını yapmak çok zor olur, özellikle değişiklik yapmak çok maliyetli hale gelir.

PMD‘nin Coupling ölçütünün ölçümlerinden birisi de LawOfDemeter’dir ve burada bahsettigimiz prensibe uymayan erişimleri raporlar.

Kodda bu kuralı ihlal eden en temel kalıp, zincirleme erişimdir. Yani

...
Object o = a.getB().getC().getD().calculate();
...

şeklindeki kullanımlar aslında birbirlerinden hiç haberdar olmayan a nesnesi ve D‘nin nesnesini birbirine bağımlı kılar. Bir başka deyişle a nesnesi, hiç gerekmediği halde D‘nin nesnesini bilir, onun API’sinden haberdar olur, dondürdüğü değeri alır.

Bu tür zincirleme erişimlerin makul olabileceği yerleri düşündüğümüzde ilk akla gelen web katmanındaki view yapılarıdır. Örneğin, Java’nin web bileşenlerinden JSF kullandığınızda, view sayfalarında, arkadaki managed beanlere ulaşırken bu şekilde zincirleme özellik ulaşımı yaparsınız. Pek çok Java EE yapısı da açıkçası bu şekilde zincirleme erişimle çalışır. Fakat iş mantığı içınde ya da örneğin katmanlar arasında bu şekilde kısa yollar kurmak son derece sıkıntılıdır.

Demeter kuralı önemlidir, uyarak kod yazmak kodumuzu çok daha kaliteli kılacaktır.

 

Bu yazı toplam 838 defa görüntülenmiştir.