BİR SINIFIN ANATOMİSİ
Sınıf, belli özelliklere göre nesneleri gruplamaktır. Örneğin; çam, meşe vs
gibi nesneler ağaç olarak sınıflandırılabilir. Aynı şekilde ağaç, çiçek, ot
gibi sınıflar da gruplanarak bir üst sınıf olan bitkiler sınıfını oluşturur.
Bitkiler, insanlar, hayvanlar da gruplanarak canlılar sınıfını oluşturmaktadır.
Bu ağaç yapısını kökten başlayarak analiz edecek olursak; canlılar sınıfı temel
sınıftır. Bitkiler, insanlar, hayvanlar bu temel sınıftan türemiş sınıflardır.
Ağaç, çiçek, ot ise bitkiler sınıfından türemiş sınıflardır. En sonda ise çam,
meşe vs. ağaç sınıfından türemiş nesnelerdir. Her sınıfın belli başlı
özellikleri ve fonksiyonları vardır. Örneğin; ağaç sınıfının türü, boyu vs.
gibi özellikleri ve fotosentez yapma gibi fonksiyonları vardır. Ağaç sınıfından
türeyen her nesne bu temel özellikleri ve fonksiyonları miras almaktadır. Nesne
yönelimli programlamadaki sınıf kavramının bu benzetmeden farkı yoktur. Bu
makalede sınıf kavramı üzerinde duracağız. Sınıflar yazacak, türetme yapacak ve
sınıflarda neler bulunur, bunları inceleyeceğiz.
Örnek olarak "Canlilar" sınıfını yazacak, sonra
"Canlilar" sınıfından "Insan" sınıfını türetecek ve
nihayetinde "Insan" sınıfından "Sercan" nesnesini
oluşturacağız. Bu süreç içerisinde sınıflar içerisinde kullanılan alanlardan,
özelliklerden, fonksiyonlardan, metodlardan, yapıcılardan, temsilcilerden yeri
geldikçe bahsedeceğiz. Yapıcı metodlar ile başlayalım.
Bir sınıfın yeni bir kopyası oluşturulurken, sınıfın yapıcı metodu
çalışmaktadır. Yapıcı metod sınıf ile aynı ada sahiptir. Varsayılan yapıcı
metod parametre almaz. Ancak çeşitli parametreleri vererek birden fazla yapıcı
metod tanımlayabiliriz. Buna aşırı yükleme denilmektedir. Yapıcı metod
tanımlarken dikkat edilmesi gereken nokta metodun sınıf ile aynı ada sahip olması ve birden fazla yapıcı metod
tanımlanmış ise metodların parametre sayılarının veya parametre türlerinin
birbirinden farklı olmasıdır. Aşağıda "Canlilar" sınıfımız
ve yapılandırıcıları verilmiştir.
class Canlilar
{
private static string tur;
private static int yas;
public Canlilar()
{
}
public Canlilar(string turu)
{
tur = turu;
}
public Canlilar(string turu, int yasi)
{
tur = turu;
yas = yasi;
}
}
İlk yapılandırıcımız varsayılan yapılandırıcıdır. Nesne herhangi bir
parametre almadan oluşturulur. İkinci yapılandırıcımız canlının tür bilgisini
alarak "Canlilar" sınıfının kopyasını oluşturmaktadır. Üçüncü
metodumuz ise tür ve yaş bilgilerini alarak sınıfımızın kopyasını
oluşturmaktadır. "Canlilar" sınıfını oluştururken girdiğimiz bu
parametreler sınıf içerisinde tanımlanan "tur" ve "yas"
değişkenlerine aktarılarak sınıf içerisindeki işlemlerde kullanılmaktadır.
Değişkenleri ve yapıcıları tanımlarken private ve public belirteçlerini kullandık. Private
belirteci tanımlanan değişkenin, metodun vs. sadece o sınıf içerisinden
erişilebileceğini belirtmektedir. Aksi belirtilmediği sürece bütün değişkenler,
metodlar private tanımlanmıştır. Public belirteci ile tanımlanan değişkenlere,
metodlara vs. bütün sınıflardan erişim sağlanmaktadır. Bu iki belirtecin
dışında hem sınıf içerisinden hem de referans gösterildiği diğer sınıflardan
erişim sağlayan protected, içinde bulunduğu
sınıfa ait assembyl tarafından erişim sağlayan internal belirteçleri vardır.
Her canlı sınıfının bir türü vardır. Tür, canlılar sınıfının sahip olduğu
bir özelliktir. Şimdi Canlılar sınıfımıza tür özelliğini ekleyelim.
public string Tur
{
get { return tur; }
set { tur = value; }
}
"Tur" özelliği hem dışarıdan değer alan hemde içerdiği değeri
çağrıldığı yere aktaran bir yapıdadır. Yani hem okunabilir hem yazılabilir. Set
bloğunda aldığı değeri "tur" değişkenine aktarır. Get bloğunda ise
"tur" değişkeninin değerini çağrıldığı yere return eder. Özellikler
ReadOnly'de olabilir. Bunun için sadece get bloğu yazılır.
public string SinifBilgisi
{
get { return "Canlilar sınıfı."; }
}
"SinifBilgisi" adlı bu özellik kullanıldığında "Canlılar
sınıfı." stringini return eder. "SinifBilgisi" özelliğine değer
atadığımızda bu özelliğin ReadOnly olduğunu belirten bir hata ile karşılaşırız.
Özelliklerin yanında sınıflarda bazı işlevleri yerine getiren fonksiyonlar
olabilir. Örnek olarak "Canlilar" sınıfımızda dışarıdan canlının
doğum tarihini alıp geriye yaşını return eden bir fonksiyon olsun.
public int YasHesapla(DateTime
dogumTar)
{
int dogumTarihi
= dogumTar.Year;
yas = Convert.ToInt32(DateTime.Now.Year) - dogumTarihi;
return yas;
}
Bir sınıf içerisinde yazdığımız bir fonksiyonun içeriğine, bu sınıftan
türettiğimiz bir sınıfta eklemeler yapabilir veya içeriğini tamamen
değiştirebiliriz. Bunun için sonradan içeriğine müdahele edebileceğimiz
metodları virtual olarak tanımlamalıyız.
Virtual metodlara, bu metodların bulunduğu sınıftan türemiş sınıflarda müdahele
edilebilir. Örnek olarak canlılar sınıfımızda "TurYaz" adında
canlının türünü ve yaşını return eden virtual bir metodu olsun.
public virtual string TurYaz()
{
return tur+"
"+yas.ToString();
}
Şimdi, "Canlılar" sınıfından "Insan" sınıfını
türetelim. Sınıf isminden sonra ":" koyup
türeteceğimiz sınıfın ismini yazıyoruz. Unutmamak gerekir ki bir sınıf ancak
bir tek sınıftan türeyebilir. Çoklu kalıtım için ilerleyen satırlarda
değineceğimiz arayüzler(Interface) kullanılır.
class Insan:Canlilar
{
}
"Insan" sınıfını "Canlilar" sınıfından türettik. Artık
"Insan" sınıfımız da yukarıda "Canlilar" sınıfı için
yazdığımız "Tur" ve "SinifBilgisi" özellikleri ile
"YasHesapla" ve "TurYaz" metodlarına sahiptir. Bu üyeler
static tanımlanmadığından direkt erişilemezler. Öncelikle "Insan"
sınıfından bir kopya oluşturmamız gerekmektedir. Hem buna hemde virtual
metodların içeriğine müdahele edilmesine örnek olarak "Insan"
sınıfımzıda "TurYaz" metodunu override edelim.
class Insan:Canlilar
{
private string ad;
public override string TurYaz()
{
Insan yeni = new Insan();
yeni.Tur = "Insan";
return "Bu
canlı " + yeni.Tur+".Adı "+ad;
}
public string Ad
{
get { return ad; }
set { ad = value; }
}
}
İnsan sınıfının bir kopyasını oluşturduk. Bu şekilde "Tur"
özelliğine erişebildik. Intellisense özelliği ile bunu gözlemleyebiliriz.
1.Şekil: Static tanımlama
Yukarıdaki koda geri dönersek, görüldüğü gibi "Insan" sınıfında
"Tur" adında bir özellik tanımlamamamıza rağmen bu özelliği
"Canlilar" sınıfından miras aldığı için kullanabiliyoruz.
"Canlilar" sınıfından miras aldığı özellikler yanında sınıfımıza
"Ad" adında yeni bir özellik ekledik. Yani sınıflarımıza türettiğimiz
sınıfın özellikleri yanında yeni özellikler, fonksiyonlar vs. ekleyebiliriz.
"TurYaz" metodunu "Canlilar" sınıfında tanımlamıştık ve kalıtım
yolu ile "İnsan" sınıfına aktarmıştık. "Insan" sınıfından
yeni bir üye tanımladığımızda ve "TurYaz" metodunu kullanmak
istediğimizde ne olacak? Bu metodu kullandığımızda "Canlilar"
sınıfındaki metodumuzda yazdığımız işlemler gerçekleşmeyecektir. Sebebi bu
metodu "Insan" sınıfında override etmemizdir. Dolaysı ile
"TurYaz" metodunu kullandığımızda yukarıda da görüldüğü gibi "Bu
canlı " + canlının türü+".Adı "+canlının adı" katarı return
edecektir. "Insan" sınıfından türeyen üçüncü bir sınıf daha yazalım.
class Sercan:Insan
{
public static void AdYaz()
{
Insan yeni = new Insan();
yeni.Ad = "Sercan YILMAZ";
MessageBox.Show(yeni.TurYaz());
}
}
"Sercan" sınıfı "Insan" sınıfından türemektedir.
"AdYaz" adında bir metoda sahiptir. Bu metod içerisinde insanın adını
bildiriyoruz. Bir mesaj penceresinde "TurYaz" metodunu
çalıştırıyoruz. Bu satırda yukarıda override ettiğimiz metod çalışacaktır. Bu
metod içerisinde canlı türünü "insan" olarak belirlemiştik. Geriye
"Bu canlı insan.Adı Sercan Yılmaz" stringi return edecektir. Dolaysı
ile mesaj penceresinde bu yazı görüntülenecektir. Bunun gibi .NET'in virtual
metodlarını da override edebiliriz. Örnek olarak sıklıkla kullandığımız
ToString() metodu sanal bir metoddur. Dolaysı ile override edebiliriz. Örnek
olarak "Sercan" sınıfında bu metodu;
public override string ToString()
{
return "ToString
metodu override yapıldı.";
}
şeklinde override edersem bu sınıfta ve bu sınıftan türetilen sınıflarda
ToString() metodunu kullandığımızda "ToString metodu override
yapıldı." katarı geriye dönecektir. "Canlilar" sınıfında
"TurYaz" sanal metodunu yazdık. "Insan" sınıfında override
ettik. "Sercan" sınıfında kullandık. Peki "Insan" sınıfında
"Canlilar" sınıfındaki "TurYaz" metodunu nasıl
kullanabilirim? Yani override edilmiş metodu değil de sanal metodu nasıl
kullanabilirim. Bunun için "base" ifadesini kullanıyoruz. "Insan"
sınıfında aşağıdaki metodu yazalım.
public string Turu()
{
return base.TurYaz();
}
Yukarıdaki "Turu" metodunun yaptığı iş taban sınıfın
"TurYaz" metodundan dönen değeri return etmektir.
Son olarak event ekleyelim. Bildiğiniz gibi eventlar belli bir iş
sonrasında tetiklenen metodlardır. Mesela buton tıklandığında Click olayı
tetiklenir yada form yüklendiğinde Load olayı tetiklenir. Bunların dışında
kendimiz de event yazabiliriz. Eventlar delegate türünden tanımlanır.
Delegateler program içerisinde bir yada daha fazla metodu gösteren referans türünden
nesnelerdir. Delegate tanımı aşağıdaki gibidir.
public delegate void Temsilci();
"void" temsilcinin(delegate) temsil ettiği metodun dönüş tipidir.
Eğer temsil edilecek metod dışarıdan parametre alıyorsa bu da temsilcide
belirtilmelidir. Mesela string bir değer return eden ve int türünden bir
parametre alan metodu temsil eden delegate aşağıdaki gibi tanımlanır.
public delegate string Temsilci(int sayi);
"Sercan" sınıfında aşağıdaki gibi küçük bir event oluşturalım.
public string adim;
private delegate void Temsilci();
private event Temsilci
Olay;
public void OlayOlustur()
{
Olay += new Temsilci(Sercan_Olay);
if (adim = =
"Sercan")
{
Olay();
}
}
public void Sercan_Olay()
{
MessageBox.Show("Event çalıştı. ");
}
Önce eventı tanımlayacağımız temsilciyi tanımlıyoruz. Sonra eventı
tanımlıyoruz. "OlayOlustur" adlı metodda önce tanımladığımız eventı
oluşturuyor sonra eventı tetikliyoruz. Sınıf içerisindeki "adim"
değişkeni "Sercan" değerini aldığında olay tetiklenmektedir. Sercan_Olay()
metodu eventımızın çalıştıracağız metoddur.. Başka bir sınıfta;
Sercan
yeni = new Sercan();
yeni.OlayOlustur();
şeklinde "Sercan" sınıfının "OlayOlustur" adlı metodunu
çalıştırırsak Sercan_Olay() eventı tetiklenir ve "Event tetiklendi."
mesajı alınır. Bunun gibi herhangi bir işlem gerçekleştiğinde farklı işlerin
tetiklenmesini istediğimizde kendi eventlarımızı yazabiliriz.
Sınıflarımız büyüdükçe takibide zorlaşmaktadır. Sınıfımızda neler
kullandığımızı görmek için sınıfımızda kullandığımız metodları, özellikleri,
olayları ve indeksleyicileri bir arayüz içerisinde tanımlarız.
"Canlilar" sınıfımız için aşağıdaki gibi bir Interface yazabiliriz.
interface ICanlilar
{
int YasHesapla(DateTime
dogum);
string Tur
{
get;
set;
}
string SinifBilgisi
{
get;
}
string TurYaz();
}
Görüldüğü gibi tanımlamalarda public, private gibi belirteç
kullanılmamaktadır. Arayüzlerdeki tüm üyeler varsayılan olarak public'tir.
"Canlilar" sınıfımızı bu arayüzden türetiyoruz. Arayüzlerden
türetilen sınıflar arayüzlerde tanımlanan üyelerin hepsini kullanmak
zorundadır. Yukarıda bir sınıfı ancak tek sınıftan türetebildiğimizi ifade
etmiştik. Çoklu kalıtımı arayüzlerle gerçekleştiriyoruz. Birden fazla arayüz
yazıp aşağıdaki gibi bir sınıfı bu arayüzlerden türetebiliriz.
class Canlilar:ICanlilar,ICanlilarYeni
{
}
Bu makaleden öğrendiklerimizi özetleyecek olursak;
- Sınıf ve sınıf öğeleri
(Constructer, Property, Event, Function, Event) tanımlama.
- Erişim belirteçleri(Public,
Private, Protected, Internal)
- Virtual metod kullanma ve
override işlemi
- Kalıtım
- Arayüz(Interface) tanımlama ve çoklu
kalıtım
İş hayatının bu kadar yoğun olacağını düşünmemiştim:) Sonraki makalede
görüşmek üzere.Bizden ayrılmayın:)
BİR SINIFIN ANATOMİSİ
class Canlilar
{ private static string tur; private static int yas; public Canlilar() { } public Canlilar(string turu) { tur = turu; } public Canlilar(string turu, int yasi) { tur = turu; yas = yasi; } } |
public string Tur
{ get { return tur; } set { tur = value; } } |
public string SinifBilgisi
{ get { return "Canlilar sınıfı."; } } |
public int YasHesapla(DateTime
dogumTar)
{ int dogumTarihi = dogumTar.Year; yas = Convert.ToInt32(DateTime.Now.Year) - dogumTarihi; return yas; } |
public virtual string TurYaz()
{ return tur+" "+yas.ToString(); } |
class Insan:Canlilar
{
}
|
class Insan:Canlilar
{ private string ad; public override string TurYaz() { Insan yeni = new Insan(); yeni.Tur = "Insan"; return "Bu canlı " + yeni.Tur+".Adı "+ad; } public string Ad { get { return ad; } set { ad = value; } } } |
class Sercan:Insan
{ public static void AdYaz() { Insan yeni = new Insan(); yeni.Ad = "Sercan YILMAZ"; MessageBox.Show(yeni.TurYaz()); } } |
public override string ToString()
{ return "ToString metodu override yapıldı."; } |
public string Turu()
{ return base.TurYaz(); } |
public delegate void Temsilci();
|
public delegate string Temsilci(int sayi);
|
public string adim;
private delegate void Temsilci(); private event Temsilci Olay; public void OlayOlustur() { Olay += new Temsilci(Sercan_Olay); if (adim = = "Sercan") { Olay(); } } public void Sercan_Olay() { MessageBox.Show("Event çalıştı. "); } |
Sercan
yeni = new Sercan();
yeni.OlayOlustur(); |
interface ICanlilar
{ int YasHesapla(DateTime dogum); string Tur { get; set; } string SinifBilgisi { get; } string TurYaz(); } |
class Canlilar:ICanlilar,ICanlilarYeni
{
}
|
Hiç yorum yok:
Yorum Gönder