21 Şubat 2010 Pazar

Erişim kısıtlamaları (Access Modifiers)

Erişim kısıtlamalarına (Access Modifiers) girmeden önce bazı şeyleri anlatmak ve/veya açığa kavuşturmak istiyorum. İlk mesele java bilenlerin aşina olduğu paket mantığıdır. Paket mantığı C++ (C#) da isim uzayları(namespace) ile aynıdır. Peki paket mantığı nedir? Bir dil büyüdükce ve onu destekleyen kütüphaneler arttıkca bazı meseleler kendini gösterir. Örneğin sınıf adlarına isim bulma konusu büyük bir dert olabilir. Yazdığınız bir programda iki kütüphane olsun. Birisi dosya formatı olarak XML'yi kullanmak için XML kütüphanesi diğeri ise XML dosyasındaki verileri kullanarak belirli bir veriyi işleyecek matematik kütüphanesi olsun. Şimdi bu kütüphaneler içinde XML dosyasını işlemek için Process sınıfı ve matematik kütüphanesinde veriyi işleyecek Process sınıfı olsun. Bu durumda derleyici hangi sınıfı kullanmak istediğinizi nasıl ayırt edecek. İşte bu duruma javanın yaklaşımı paket (Package) C++'ın ise isim uzayıdır. Örneğimize göre XML kütüphanesinde Process sınıfı w3c.xml.core paketinde yer alabilirken matematik kütüphanesinde org.dataminening.core paketinde yer alır. Bu durumda derleyici hangi durumda hangi sınıfı kullanacağını sınıfın önüne paket ismini koymamızdan dolayı biliyordur.

Örnek:
w3c.xml.core.Process processXml = new w3c.xml.core.Process();
org.dataminening.core.Process processData = new w3c.xml.core.Process();
Fiziksel olarak paketler diskiniz üzerinde iç içe geçmiş dizinlerden oluşur.

Örnek: w3c dizininin içinde xml dizini xml dizinin içinde de core dizini ve core dizininin içinde de Process klas dosyası vardır.

Aynı seviyede dosyalar olabilir. w3c dosyasının içinde html dosyası v.s. gibi.

Paket mevzu JavaFX de de aynı şekildedir. Bunu anlatmamın sebebi bir çok JavaFX script dosyasının olacağı ve bu dosyaların belirli görevler için belirli paketlerde toplanmasının uygun olacağıdır.
Örneğin bütün matematik sınıflarının Math paketinde ya da alt paketler şeklinde (math.trigonometry math.polynomial v.s)

Gelelim ikinci meseleye: Java JavaFX'e göre daha katı kuralları olan bir dil demiştik. Ancak java ile JavaFX arasındaki bu farkın sebebi belli. Java bir dil JavaFX bir script dili.
Aradaki farklar ise (ki sadece konuyla ilgili olanları ele alacağım) :
  1. Javada sınıfları (arayüzler v.s) tek bir dosyada ya da ayrı ayrı dosyalarda yazabilirsiniz. Ancak sınıflar arası bilgi alışverişi aynı dosya veya ayrı dosya da olmaları bakımından bir fark oluşturmaz ve dosya sadece bir metni (kaynak kodu) tutar. Fakat JavaFX de her dosya aynı zaman da bir script dosyası demektir ve buna göre bazı ilişkiler değişir.
  2. Java da sınıf (arayüzler v.s.) dışında değişken ve/veya metod (fonksiyon) tanımlanamaz. JavaFX de ise bir script dosyasında bir fonksiyon(metod) ve/veya değişken tanımlanabilir.
Örneğin:
person.java kaynak dosyası:
class Person {
....
}
class Employer extends Person {
...
}
Person person = new Person(); // Derleyici hata verir. Java dili böyle bir özellik desteklemez.
int count = 0; // Derleyici hata verir. Java dili böyle bir özellik desteklemez.
Person getPerson () {
...
} // Derleyici hata verir. Java dili böyle bir özellik desteklemez.
person.fx kaynak dosyası:
class Person {
....
}
class Employer extends  Person {
...
}
var person =  Person{}; //  Problem yok JavaFX bu deklerasyonu doğru kabul eder.

var count = 0; // Problem yok JavaFX bu deklerasyonu doğru kabul eder.
function getPerson ():Person {
...
} // Problem yok JavaFX bu deklerasyonu doğru kabul eder.
Tüm bu meselelerden sonra erişim konusunun önünde açıklanması gereken son bir mesele kaldı. Sınıf sınıfların kalıtımı ve paket erişiminin ilişkileri.
Benzer işleri yapan sınıfları aynı paketlere yerleştirmek gerekliliği doğal olarak açıktır. Örneğin Swing kütüphanesindeki kullanıcı arayüzü bileşenleri javax.swing paketinde yer alır. Aynı paket ile farklı paketler arasında erişim durumları söz konusudur. Sınıflar arası ise kalıtım mekanizmasından dolayı meydana gelen erişimler söz konusudur. Tüm bunlar büyük bloklara erişim gibidir. Şöyle ki sınıfa erişmek programın büyük parçalarına erişmektir. Halbuki daha küçük fonksiyonel parçalar vardır ki bunlar ise bir değişken ve/veya metot olabilir. Maddeler halinde özetlersek erişilebilecek şeyler şunlardır:

  1. Sınıflara erişim durumları (Başka paketten sınıf diğer paketten sınıfı genişletebilir ya da genişletemez.)
  2. Değişkenlere erişim durumları (Alt sınıf, farklı paketten sınıf)
  3. Metotlara erişim durumları (Alt sınıf, farklı paketten sınıf)
Peki bu mekanizmalar neden gerekli. Tabiki kodu kendinizden yada bir başkasından korumak için. Bazen geliştirici kodu kendi istediğini yaptırmak için değiştirir. Örneğin kafanızda bir plan var ve bunun için bir kütüphane kullanıyorsunuz. Kütüphanenin bir sınıfındaki değişkenin erişim kısıtlaması olmadan kullanıldığını düşünelim. Siz doğal olarak kütüphanenin bu değişkeninin içeriğini sizin aleyhinize değiştirmek isteyeceksiniz. Peki bu kütüphanenin kaynak koduna erişiminizin olmadığını düşünecek olursak bunun sonuçları ne olacaktır. Şöyle ki kod açık kaynaklı olsaydı siz içeriğini değiştireceğiniz değişkenin meydana getireceği yan etkileri tahmin edebilirdiniz.Örneğin bir veritabanını yönetiyorsanız bütün tabloları erişilmez yapabilirsiniz mesela. Diyelim ki kaynak kodu mevcut. Bu durumda çok basit bir kütüphane değilse sonradan oluşacak yan etkileri nerden bilebilirsiniz?!
Bazen de beraber çalışan bir grup programcı birbiri ile ilişkili kütüphaneleri yazarken bir diğerinin yaptığını yıkabilir ya da uzun süre dokunmadığınız ve çok açıklayıcı olmadığınız koda geri döndüğünüzde işleri karıştırabilirsiniz. Son olarak (ki en önemlisi) bazı kodlar kötü niyetli yazarlar tarafından kullanılabilir. Örneğin Appletların çoğu durumda yerel kaynaklara erişimi yoktur. Yerel kaynaklara erişimi kısıtlayan değişkenin değerini değiştirerek yazar kullanıcının dosyalarına erişebilir.

Paketti script dosyasıydı ayrı paketlerdeki sınıflardı derken geldik asıl olaya:

Erişim kısıtlamalarının anahtar kelimeleri vardır. Bu anahtar kelimeler önüne geldikleri ögeye göre erişim yetkilerini değiştiriyor. Peki bu kelimeler nelerdir.
  1. public (genel erişim).
  2. public-read (yanlızca okumak için genel erişim ve sadece değişkenlere uygulanabilir.)
  3. public-init (yanlızca kullanıma hazırlamak için ve sadece değişkenlere uygulanabilir.)
  4. protected (korunmuş)
  5. package (paket seviyesinde)
Public, protected java'dan tanıdık ama diğerleri özellikle package hem yani hem de kafa karıştırıcı. Peki private (özel ya da gizli diyebilirsiniz) nerde. Private JavaFX de öntanımlı erişim. Yani siz bir sınıfın fonksiyonun ve değişkenin önüne bu anahtar kelimeleri eklemezseniz private olarak kısıtlanmış olur.  Package ise değişken sınıf ve functionların önüne geleceği için paket tanımlamasından ayrılır. Zaten paket tanımlaması dosyanın en başında yapılır ve sadece aralarında noktalar bulununan dosya hiyerarşisi ile ifade edilir.
Şimdi bu anahtar kelimeleri bir inceleyelim.

Public adı üzerinde herkese açıktır. Örneğin:
public var isim = "";

public function topla(x:Integer, y:Integer):Integer{ return x+y; } //JavaFX de son satırda return ve ";" gerek yoktur.

public class araba {
        var model:String;
}
Bu sınıf, değişken ve fonksiyonlara herhangi bir yerden yani aynı paketteki yada ayrı paketteki script dosyaları ve sınıflardan v.s ulaşabilirsiniz.

Protected ise korunmuş anlamındadır. Korumadan kasıt eğer bir sınıf diğerini genişletiyorsa aynı paket içerisinde de olsa ayrı paket içerisindede olsa sınıf, değişken yada fonksiyona erişimi vardır. Sınıfların önüne protected gelmesi JavaFX de yenidir. Yani java da class anahtar kelimesinin önüne protected kelimesi gelmez. Aslında bir script dosyası derlendiği zaman bir java sınıfı haline gelir. Dolayısı ile protected sınıf olası ve mantıklı bir yaklaşım.
protected var isim = "";

protected function topla(x:Integer,  y:Integer):Integer{ return x+y; } //JavaFX de son satırda return ve ";"  gerek yoktur.

protected class araba {
        var  model:String;
}
Package anahtar kelimesi ise önüne geldiği sınıf, değişken ve fonksiyonun sadece aynı pakette bulunan sınıflar tarafından ulaşılmasını sağlar. Bu davranış java da eğer bir değişkenin, sınıfın ve fonksiyonun önüne hiç bir erişim kısıtlaması anahtar kelimeleri getirmezseniz mümkündür(JavaFX de aynı davranışın script dosyaları için geçerli olduğunu hatırlayın).
package org.karakan.tamer; // Burada paket tanımı var. Bu tanımı bir erişim kısıtlayıcı anahtar kelimesi olan package ile karıştırmayın.

package var isim = ""; 

package function topla(x:Integer,  y:Integer):Integer{ return x+y; } //JavaFX de  son satırda return ve ";"  gerek yoktur.

package class araba {
        var  model:String;
}
public-read anahtar kelimesi yanlızca değişkenler için kullanılır. public-read ile ilgili kurallar:
  1. Her yerden okunabilir. (Farklı paketteki sınıftan aynı yada farklı script dosyasından v.s ). Fakat her yerden değeri değiştirişemez.
  2. Eğer script dosyasında tanımlanmışsa o tanımlandığı dosyadan yeniden değer atanabilir.
  3. Eğer sınıf içinde deklere edilmişse o sınıfın veya sınıfı genişleten ve aynı script dosyası içindeki diğer sınıftan yeniden değer atanabilir.
  4. Başka bir script dosyasında tanımlanan sınıfı diğer script dosyasındaki sınıfı genişletse bile değişkene yeni değer atayamaz.
Aslında public-read tek başına yada package veya protected ile birlikte kullanılabilir. Package ve protected anahtar kelimesinin değişkenin değerinin okunmasına bir etkisi yoktur. Etkisi değişkeninin değerinin değiştirilmesi üzerinedir. Başına package gelen değişkenin kuralları:
  1. Her yerden okunabilir. (Farklı paketteki sınıftan aynı yada farklı script dosyasından v.s ). Fakat her yerden değeri değiştirişemez.
  2. Paket içindeki tüm script dosyalarından değeri değiştirlebilir.
  3. Eğer sınıf içinde deklere edilmişse o sınıfın veya sınıfı genişleten ve aynı script dosyası içindeki diğer sınıftan yeniden değer atanabilir.
  4.  Başka bir script dosyasında tanımlanan fakat aynı paketteki sınıf diğer sınıfı genişletiyorsa değişkenin değerini değiştirebilir.
Eğer public-read in başına protected kelimesi gerekirse: Başka bir script dosyasında tanımlanan fakat ayrı paketteki sınıf diğer sınıfı genişletiyorsa değişkenin değerini değiştiremez.

public-init için public-read için geçerli olan herşey geçerli. Farklı olan ise public-init olan bir değişkene heryerden ilk değer atanabilir demek. İlk değeri atadıktan sonra onu değiştirmeye kalkarsanız public-read kuralları ile karşı karşıya kalırsınız.
public-read var id=12;
package public-read var id=12; 
protected public-read var id=12;
  
public-init var serialNumber = "cdRT1045" 
package public-init var serialNumber = "cdRT1045"
protected public-init var serialNumber = "cdRT1045"
Sanırım erişim kısıtlamaları (erişim kontrolcüleri)hakkında söyleyebileceklerim bu kadar.