4 Temmuz 2013 Perşembe

C# 'ta Kapsülleme, Erişim Belirteçleri ve Polymorphism

.Net Framework'ünde ne gibi farklılıklar var diyeceksiniz? Öncelikle .Net Framework'ünde gelen yeniliklerden bahsedelim.
I. Erişim belirteçlerinin(Access Modifiers) varlığı kapsüllemeyi çok daha rahat yapabilmemize olanak sağlar. Bu sayede bir metod veya bir değişken anahtar sözcükler(keywords) aracılığıyla sadece önceden belirlenen sınırlar dahilinde kullanılabilir. Yada bunlara belirlenen sınırlar içinden ulaşılabilir. Burada bahsedilen keyword'leri birazdan açıklayacağım. (Tabii ki C#'ta kullanılan keywordleri açıklayacağım. Ve kullanımlarını basitçe anlatacağım.)
II. Özellik(Property) Sahalarının kullanımı (Bunun yapımını ilerde C# kodu ile göstereceğim.) Bu sayede .Net Framework kapsüllemeyi destekler.
III. Soyut sınıf(abstract class) ve soyut metodların(abstract methods) kullanımı. Aslında kalıtım(inheritance) konusunu anlatırken taban sınıfımız(base class) soyut sınıf idi. Onun için bu kısmı sadece açıklayacağım. Örnek vermeyeceğim. Örneği görmek isteyenler miras(inheritance) konusunu anlattığım yazıdaki örneği incelerlerse istedikleri bilgiye ulaşabilirler.
Evet bu kadarlık giriş yeter. Şimdi yukarıda anlattığım 3 maddeyi enine boyuna tartışalım.
I. Erişim belirteçlerinin ne işe yaradıklarından yukarıda bahsettiğim için burada direkt erişim belirteçlerinin neler olduklarını yazalım ve erişim sınırlarını çizelim. Erişim sınırları geniş olandan dar olana doğru bir sıralama yaparsak.
·         public: Bütün her yerden erişilmek istenen veriler public anahtar sözcüğü ile birlikte kullanılır. Sadece aynı proje içerisinden değil diğer projeler içerisinden de erişilebilir.
·         internal: Aynı assembly içindeki tüm sınıflar erişebilir. Yani public anahtar sözcüğünün sadece aynı proje içinden erişilebileni. (VB .Net'te ise Friend anahtar sözcüğüne karşılık gelir.)
·         protected: Protected anahtar sözcüğü ile birlikte kullanılan verilere ise sadece bir alt sınıfa kadar erişilebilir.
·         private: Bu ise sadece tanımlandığı sınıfta geçerli olan veriler için kullanılır.
Ancak kontrollerde(controller) yaygın olan kullanım şekli kontrollerin dışarıdan erişilmesi istenen metodlarının(aynı anda diyelim ki 3 tane kontrol'ün belli metodlarının çalışması gerekli olabilir.) public anahtar sözcüğü kullanılan bir metod içinde tanımlanmasıdır. Şimdi bu durumun nasıl yapıldığını gösteren mini bir örnek kod yazalım. Kodda belirtilen kontrollerin daha önceden tanımlanmış olduğunu düşünelim.

public void ChangeColor(Color color)
{
this.groupBoxLine.BackColor = color;
this.groupBoxOutCity.BackColor = color;
this.groupBoxExternalPriceDetails.BackColor = color;
this.groupBoxInternalPriceDetails.BackColor = color;
this.groupBoxUser.BackColor = color;
this.groupBox1.BackColor = color;
this.btnAddNewLine.BackColor = color;
this.btnAddNewUser.BackColor = color;
this.btnCentralReport.BackColor = color;
this.btnChangePassword.BackColor = color;
this.btnDeleteExternalLine.BackColor = color;
this.btnDeleteInternalLine.BackColor = color;
this.btnDeleteUser.BackColor = color;
this.btnExit.BackColor = color;
}

Yukarıdaki metod bir renk parametresi gönderilerek çağrıldığı zaman yukarıda yazan bütün (daha öncede private anahtar sözcüğü ile tanımlanmış olduklarını kabul etmiştik.) kontrollerin rengini gönderilen renge değiştirmeye yarıyor. Bu sayede yukarıdaki kontrollerin hepsinin BackColor dışındaki metodları dış dünyadan soyutlanmış oluyor.
Aslında yaptığımız metod public anahtar sözcüğü ile tanımlanmayıp internal anahtar sözcüğü ile de tanımlanabilir. Bu bizim metodun içindeki kontrollere ait BackColor metodlarının dış dünyadan ne kadar soyutlanmasını istediğimiza bağlıdır.
II. Özellik sahaları sınıflara ait özel(private) değişkenlerin aynı metodlar gibi dış dünyaya açılmalarını sağlıyor. Sadece okuma amaçlı dışa açılım yapılabildiği gibi hem okuma-hem yazma amaçlı bir açılım da yapılabilir. Teorik olarak sadece yazma amaçlı da bir açılım olsa da ne kadar mantıklı olur bilmem!!!! Şimdi örneklerimize geçelim.

private int currentExNumber = -1;
private int loginStatus = 0;
public int CurrentExNumber //Sadece okuma amaçlı özellik
{
get
{
return currentExNumber;
}
}
public int LoginStatus //Hem okuma hem yazma amaçlı özellik
{
get
{
return loginStatus;
}
set
{
loginStatus = value;
}
}

Şimdi yukarıdaki özellikleri kullanırken nesneadi.LoginStatus ve nesneadi.CurrentExNumber şeklinde kullanabiliriz. Yalnız dikkat etmemiz gereken CurrentExNumber kullanılacağı zaman sadece eşit işaretinin(=) sol tarafında kullanılabilecek olması. Çünkü başta da belirttiğimiz gibi sadece okuma yapabildiğimiz için get metodu var. Zaten bir değer atamaya kalkarsak hata verecektir.(Derleme esnasında özelliğin sadece okuma amaçlı olduğuna dair debug penceresinden mesaj verir.) Bu sayede de değiştirilmesini istemediğimiz ama kullanmak zorunda olduğumuz verilerin dış ortamdan hem soyutlanmasına hem de bunların dış ortama belirli izinler dahilinde açılımına izin vermiş olduk.
III. Aslında soyut sınıf ve soyut metod'dan daha önce az da olsa miras konusunu anlatırken bahsetmiştim. Ancak şimdi biraz polymorphism'den bahsederek bu kavramları biraz daha açacağım. Polymorphism kapsülleme ve miras'dan ayrı düşünülemez. Polymorphism Yunancada "çok formluluk" anlamına gelmektedir. Polymorphism ile soyut sınıf arasındaki ilşkiden bahsetmeden önce soyut sınıf ve soyut metodlarla ilgili bir iki ayrıntı daha verelim. Soyut sınıf sadece taban sınıflarında kullanılır ve yeni nesne yaratılmasında kesinlikle kullanılamaz. (Yani new anahtar sözcüğü kullanılamaz.)
Soyut metodlara gelince bunların ise soyut sınıflarda kullanılacağından bahsetmiştik. Bunun bize sağladığı avantaj bu metodların türetilen sınıflarda nasıl gerçekleştirildiğini bilmek zorunda olmamamızdır. Aslında bunu söyleyerek polymorphism'in yararından bahsetmiş olduk. Yani polymorphism veri soyutlaması yaparak sadece ilgilenmemiz gereken olaylar ve verilerle ilgilenmemize olanak sağlıyor. Bu sayede taban sınıfından türetilen ve aynı metodu farklı gerçekleştirimlerle(implementation) kullanan birden fazla sınıfa sahip olabiliyoruz. En basit örnek üçgen bir çokgen, kare de bir çokgen ve her ikisinin de bir alanı mevcut. Hemen basitçe bir taslak çıkarırsak çokgen sınıfı soyut taban sınıfı ve alan adında soyut bir metoda sahip. Üçgen ve kare sınıfları ise türetilen sınıflar ve alan metodunu istedikleri biçimde gerçekleştiriyorlar. (Bu işlemlerin nasıl yapıldığı miras konusunu anlattığım yazıda mevcuttur.)
Bir de soyut özellikler(abstract property) var. Bunların kullanımı ise soyut metodlar ile özelliklerin birlikte kullanımı ile ortaya çıkmakta. Buna bir örnek kod verirsem anlaşılması daha kolay olacaktır. Ancak bunların kullanımına çok sık rastlamadığımı belirtmem gerekir.
Sanırım aşağıdaki örnek kod parçası soyut özelliklerin kullanımını daha da netleştirmiştir.

abstract class Taban // Soyut sınıf
{
protected int CurrentExNumber = -1;

public abstract int GetCurrentExNumber// Soyut özellik
{
get;
}
}
class Turet: Taban //Turet adlı bir sınıf türetiliyor
{

public override int GetCurrentExNumber// overriding property
{
get
{
return CurrentExNumber+1;
}
}
}

Polymorphism'den bahsettik. Şimdi ise yalancı polymorphism'den bahsedelim. Aslında bir örnekle biraz daha açarsam daha net olur. Diyelim ki bir karşılaştırma metodunuz var ve hem integer hem de string veri tiplerini karşılaştırmak istiyorsunuz. Yalancı polymorphism sayesinde aynı isimde iki metod yazarak bu isteğinizi gerçekleştirebilirsiniz. Bunun için mini bir örnek kod yazalım isterseniz.
Aşağıda yazacağım metodların aynı sınıf içinde yazıldığını düşünelim. Şimdi bu metodları kullanırken metodların içinde yer aldığı sınıftan üretilen nesneninadi.karsilastir( yazdığımız anda kod tamamlayıcısı bize iki seçenek sunar biri bu metodun iki tane integer veri tipi ile çalıştığı, ikincisi ise bu metodun iki tane string veri tipi ile çalıştığıdır. Bu sayede bir arabirim ile birden fazla metod gerçekleştirilmiş olur.
Aslında bir metodun birden fazla gerçekleştirime sahip olması olayına overloading denir.
Dikkat edilmesi gereken nokta overloading ile overriding'in birbirine karıştırılmamasıdır. Unutmayın overloading'te bütün işlemler aynı sınıf içerisinde oluyor. Overriding'te ise tek bir sınıf yerine taban sınıfı ile bu sınıftan türetilen sınıflar işin içine giriyor.

public void karsilastir(int sayi1, int sayi2)
{
//Metodun iç implementasyonunu sizlere bıraktım.
}

public void karsilastir(string data1, string data2)
{
Metodun iç implementasyonunu sizlere bıraktım.
}



Hiç yorum yok:

Yorum Gönder