24 Nisan 2012 Salı

C# 'da OOP-5 Inheritance (Kalıtım)

Merhaba arkadaşlar...
OOP 'nin temellerinden olan "Inheritance" yani kalıtım konusunu inceleyeceğiz. Miras kavramı, aslında bizim gerçek hayatta sürekli olarak kullandığımız ve karşımıza çıkan bir kavram. Yeryüzündeki herşeyi nesne olarak kabul edersek, bu nesnelerin birbirleriyle belirli ölçüde benzerlik ve farklılıklar gösterdiğini görebiliriz. Örneğin biyolojide "canlıların sınıflandırılması" konusu vardır. Canlılar, bitkiler ve hayvanlar olarak ikiye ayrılır. Canlılar da omurgalı ve omurgasız olarak ikiye ayrılır. Canlılar birbiriyle benzerlik ve farklılıklarına göre ayrıla ayrıla, sınıflandırma bu şekilde devam eder. Biz de ebeveynlerimizden miras almadık mı arkadaşlar? Onlar bizim "ata" 'mız değil mi? Benzer özellik göstermiyor muyuz? İşte bu sınıflandırma işlemi, canlıların türlerine göre yapılır. Tür, "ortak bir atadan gelen benzer özelliklere sahip" nesnelerdir. İşte arkadaşlar programlamada ortak veya benzer özelliklere sahip sınıfları belirli bir sınıftan türetmeye, "kalıtım" diyoruz. Miras alınan sınıfa "base class" (temel sınıf), miras alan sınıfa yani "base" sınıfından türeyen sınıfa ise "derived class" (türemiş sınıf) diyoruz arkadaşlar.

Arkadaşlar C sharp, "multiple inheritance" (çoklu kalıtım) yapılmasına olanak vermemiştir, yapılamaz. Bir sınıf sadece bir sınıftan miras alabilir. Gerçek hayatta da bir çocuğun birden fazla babasının mümkün olamayacağı gibi. Bir sınıfa birden fazla kabiliyet eklenebilir. Programlamada bunun için "interface" sınıfları kullanılır. Bu konuyu da ilerleyen yazılarımda anlatacağım.

Peki programlamada kalıtıma neden ihtiyaç duyarız? Birbirlerine benzer class 'ları bir base class 'ından türetip, ortak değer ve davranışları (properties and methods) bu base class 'ında tanımlarız. Daha sonra bu sınıftan türeyen class 'larda bu değer ve davranışları tekrar tekrar tanımlamamıza gerek kalmaz. Türemiş class 'da class 'ın amacına göre, sadece ek değer ve davranışlar tanımlarız. Yani kalıtım kullanarak gereksiz yere kod tekrarı yapmaktan kurtuluruz. Kalıtım kullanmanın bize sağlayacağı diğer bir fayda ise class 'ları kategorilere ayırabilir, benzer class 'ları bir yerde toplayabilir, kodun okunabilirliğini arttırırız.

Örneğin bir süpermarketteki ürünlerin modellemesini yapalım. Bir "Urun" sınıfım olsun. Tüm ürünlerimizi bu sınıftan türetelim. Bu yüzden bu sınıfta tüm ürünlerimizin ortak değer ve davranışlarını tanımlamalıyım.

    public class Urun
    {
        protected string _urunAdi;
        protected decimal _urunFiyati;
        protected int _stokMiktari;

        public string UrunAdi
        {
            get { return this._urunAdi; }
            set { this._urunAdi = value; }
        }
        public decimal UrunFiyati
        {
            get { return this._urunFiyati; }
            set { this._urunFiyati = value; }
        }
        public int StokMiktari
        {
            get { return this._stokMiktari; }
            set { this._stokMiktari = value; }
        }       
        public decimal KDVLiFiyatGoster()
        {
            return this._urunFiyati * 1.08M;
        } 
    }

Sınıfımızı oluşturduk. Field ve property tanımlamalarını yaptık. Bakalım diğer yerlerden "urun" sınıfıma nasıl ulaşıyorum. Örneğin "Form_Load" eventi 'nde sınıfımın görünen değer ve davranışları :

bu şekildedir. Şimdi bu sınıfı miras alacak "bilgisayar" adında bir sınıf türetelim.

    public class Bilgisayar : Urun
    {
        private int _DiskRPMHizi;

        public int DiskRPMBilgisi
        {
            get { return this._DiskRPMHizi; }
            set { this._DiskRPMHizi = value; }
        }

        public override decimal KDVLiFiyatGoster()
        {
            return this._UrunFiyati * 1.18M;
        }
    }


Çok güzel arkadaşlar "iki nokta" ile miras aldık. Kalıtım konusunun bir diğer adı da "is a" 'dir. Yani bu örnekte "bilgisayar is a urun" (bilgisayar bir üründür) şeklinde okunur.


NOT:  "DotNet" 'te tüm sınıflar birer tiptir. Eğer bir sınıf "iki nokta" ile başka bir sınıftan miras almamışsa (sınıf adının yan tarafı boşsa), o sınıf "object" sınıfından miras almıştır (Everything is a object). Çünkü "DotNet" 'de tüm sınıflar "object" sınıfından türemişlerdir. "Object" sınıfını tüm sınıfların atasıdır. Örneğin "urun" sınıfındaki "Urun" yazısının üstüne sağ tık, "go to defination" (mouse ile üstüne geldiğimde F12 'ye basmak) dediğimizde:
 object sınıfından miras aldığını görürüz. Şimdi bakalım diğer yerlerden "bilgisayar" sınıfımın değer ve davranışlarına.
Görüldüğü üzere arkadaşlar, "urun" sınıfından miras alan, "bilgisayar" sınıfımın örneği üzerinden "urun" sınıfımdaki değer ve davranışları da görebiliyorum. Ayrıca ürünlerimi kategorilere ayırabildiğimden dolayı "bilgisayar" sınıfıma her üründe olmayacak, sadece "bilgisayar" sınıfıma özgü değer ve davranışlar da ekleyebiliyorum.

"Urun" sınıfından türeyen, "Telefon" adında bir tane daha sınıf oluşturalım ve neden kalıtıma ihtiyaç duyduğumuzu görelim.

    public class Telefon : Urun
    {
        private float _kameraPikseli;
        public float KameraPikseli
        {
            get { return _kameraPikseli; }
            set { _kameraPikseli = value; }
        }

        private bool _bluetooth;
        public bool Bluetooth
        {
            get { return _bluetooth; }
            set { _bluetooth = value; }
        }

        private short _konusmaSuresi;
        public short KonusmaSuresi
        {
            get { return _konusmaSuresi; }
            set { _konusmaSuresi = value; }
        }
    }
Yine Form_Load event 'inde "telefon" sınıfımın değer ve davranışlarını görmek istersem:
şeklinde görebilirim. Ama ben base sınıfındaki "KDVLiFiyatGoster" metodunu türemiş sınıflarımda da mı böyle kullanmak zorunda mıyım? Hayır arkadaşlar, türemiş sınıflar, base sınıfındaki metotları istedikleri gibi değiştirebilir. Bu OOP tekniğine de "Polymorphizm" (çok biçimlilik) denir. Bu konuyu ilerleyen makalelerimde ele alacağım.

Başka bir yazıda görüşmek dileğiyle, hoşçakalın...

1 yorum: