Temel Bilgiler 2.1 Nesne Tabanlı Programlama

2
Temel Bilgiler
Bu bölümde Nesne Tabanlı Programlamanın temeli olan Sınıf kavramı ve
ilgili bilgiler anlatılacaktır. Konuyu bilenler bu bölümü atlayabilirler.
2.1
Nesne Tabanlı Programlama
Günümüzde, Nesne Tabanlı Programlama (NTP), genel amaçlı programcılıkta ulaşılan bir norm haline gelmiştir. C++ ve java ile yaygınlık kazanan
Nesne tabanlı Programlama, Perl, Python ve Ruby gibi yeni dillerde yeni
gelişim alanları bulmaktadır. Python ve Ruby bir script dilinin hünerleri
yanında genel amaçlı NTP’nın programcıya sağladığı üstün niteliklere de
sahiptir. Veri tabanı, görsel arayüz, ağ ve web gibi temel uygulama alanlarında etkilidirler.
1995 yılından sonra yaygınlık kazanmaya başlayan Nesne Tabanlı
Programlama1 , bir adım daha ileri giderek, 1970 lerde yaratılan soyut veri
yapısına değişkenler yanında, o değişkenlerle işlem yapan fonksiyonları da
ekledi. Elde edilen yeni veri yapısına (veri tipi) sınıf (class) denilir. Sınıf
kavramı kalıtım ve çokbiçemlilik gibi çok önemli iki aracı programlamaya
katarken, veri yapılarında ve fonksksiyon adlarında da standartlaşmaya yol
açtı.
1
’Tabanlı’ nitelemesi gereksizdir. Yapılan işe bakılırsa, ’Nesne Programlama’ demek
daha doğrudur.
BÖLÜM 2. TEMEL BILGILER
8
2.2
Sınıf ve Nesne
(class & objects)
Sınıf, nesne için bir şablondur (template); nesneler sınıftan üretilir.
Sınıf (class) soyut bir veri tipidir. Nesne (object) onun somutlaşan bir
cismidir. Bu tanımın kendisi de çok soyut kalıyor. O nedenle örneklerle
biraz ayrıntıya inelim.
Sınıftan nesne üretmek, bir otomobil fabrikasında tasarımdan otomobil üremeye benzer.
Otomobil bir sınıftır. Sınıfın öznitelikleri vardır. Akaryakıtla çalışan
motorları, lastik tekerleri, direksiyonları, frenleri vb vardır. Marşa basınca
çalışırlar, direksiyonla dönerler, gaza basınca hızlanırlar, frene basınca dururlar . . . . Bunlar otomobilin tasarımında belirtilir.
Otomobil sınıfının sayılan öznitelikleri değişkenlerle, eylemleri metotlarla belirlenir. Otomobil sınıfı soyut bir veri yapısıdır. Ama üretilen her
otomobil somut bir varlıktır, bir nesnedir.
Bir sınıf öznitelikleri ve metotlarıyla soyut bir veri yapısıdır. O nedenle, Nesne Tabanlı Programlama’da (NTP) [Object Oriented Programming - OOP] her sınıf soyut bir veri tipidir (ADT - abstract data type);
her veri tipi bir sınıftır.
Sınıf, Altsınıf, Üstsınıf
Bitkiler çok geniş bir topluluktur. Bu topluluğu büyük bir sınıf olarak alırsak, ağaçlar onun bir alt sınıfıdır. Ağaçlar, bitkiler sınıfının bütün özeliklerine sahip olmak yanında, kendilerine özgü başka özeliklere de sahiptir.
Ağaçlar sınıfından meyve-ağaçları sınıfını, onun içinden de, diyelim, elmaağaçları sınıfını seçersek, giderek öğe sayıları azalan ama özelikleri artan
içiçe sınıflar elde ederiz:
bitkiler ⊃ ağaçlar ⊃ meyve-ağaçları ⊃ elma-ağaçları
Yukarıdaki kapsama bağıntısına göre, listede bir sınıfın solundaki sınıfa
üstsınıf, sağındaki sınıfa altsınıf denir.
2.3
Ata ve Oğul
Yukarıdaki kapsama bağıntısına göre, listede bir sınıfın solunda yer alan
sınıflara ata (ancestor), sağında yer alan sınıflara oğul (descendants) denilir.
2.3. ATA VE OĞUL
9
Listenin en sonunda yer alan elma-ağaçları, listenin en başındaki bitkiler sınıfının bütün özeliklerine sahiptir. Dolayısıyla, botanik biliminde bitkilerin özeliklerini öğrenmişsek, onları elma-ağaçları için tekrar öğrenmeye
kalkışmak, bize yeni bilgiler kazandırmaz.
OOP’de de benzer iş yapılır. Üstsınıfın özelikleri biliniyorsa, altsınıfta
onlar tekrarlanmaz.
Kalıtım - inheritance
Nesne Tabanlı Programlama’da bir sınıfı soyut bir veri yapısı olarak görüp,
özeliklerini ortaya koyduktan sonra, onun bir altsınıfında bilinen özelikleri
tekrarlamayız. Başka bir deyişle, üstsınıfın bütün özelikleri altsınıfa aynen
geçer. Buna kalıtım (inheritance) diyoruz.
Üstsınıf ⊃ sınıf ⊃ altsınıf
hiyerarşisini genişletirsek,
ata ⊃ ... ⊃ oğul
sıradüzeni (hierarchy) içinde kalıtımın varlığı ortaya çıkar. Atanın bütün
öğeleri oğula kalıtsal geçer.
Nesne (object)
Kalıtım, OOP’de çok önemli ve yararlıdır. Ama OOP’ye sınıf kavramının
girişi yalnızca kalıtım için değildir. Otomobil bir topluluğu belirten cins
adıdır. Ama benim otomobilim, otomobil sınıfına ait somut bir nesnedir.
Onun plaka numarası, markası, modeli, şasi numarası, rengi, lastik markası, koltuk döşemeleri, maksimum hızı gibi kendine özgü olan ve onu öteki
otomobillerden ayıran nitelikleri vardır. O bir cins ya da şablon değil, elle
tutulan, gözle görülen bir nesnedir.
Diyelim ki, büyük bir inşaat şirketinin tanıtım ofisinde görevliyiz.
İnşa halinde 300 konutluk bir siteyi müşterilere tanıtmak için, 300 konutun
her birisi için özelikleri ayrı ayrı yazmayız. Onun yerine tek bir listeye 300
konutun ortak özeliklerini yazarız. Bu yazdıklarımız dairelerin ortak özelikleridir. Ama müşteri belirli bir daireye talip olursa, o dairenin hangi katta
olduğu, hangi cepheye baktığı gibi belli bir konuta özgü nitelikleri ayrıca
söyleyebiliriz. Son söylediklerimiz sınıfa değil, belirli somut bir konuta ait
bilgilerdir.
OOP’de sınıfa ait bir öğe o sınıftan türemiş bir nesnesidir (instance).
Nesne, sınıfın bütün özeliklerine sahiptir. Ortak olanlar yanında kendine
BÖLÜM 2. TEMEL BILGILER
10
özgü özelikleri de olabilir.
Otomobil örneğine dönersek, marka, model, renk gibi niteliklerin her
birisi otomobilin bir özniteliğidir. Her özniteliği (attribute) bir değişkenle
belirleriz. Otomobilin yürümesi, hızlanması, dönmesi, durması gibi hareketler onun eylemleridir, davranışlarıdır. Otomobilin her eylemini bir metotla
belirleriz.
Soyut Veri Yapısı - ADT
Genel anlayışa göre, OOP’nin nesneleri (object), gerçek ya da sanal dünyadaki nesneler gibidir. Nesnelerin öznitelikleri (attributes) değişkenlere
atanan değerlerle, eylemleri ise metotlarla belirlenir. Kısaca, OOP’de sınıf (class) bir işle ilgili verileri ve metotları içeren bir birimdir. Buna soyut
veri yapısı - SVY (abstract data types -ADT) denilir [4].
OOP’de soyut veri yapıları sınıflar (class) ile belirlenir.
Sınıf bildiriminin sözdizimi şöyledir:
Liste 2.1.
1
6
# sınıf bildirimi
c l a s s class_adı
#i s t e n i r s e s ı n ı f dökümanı i ç i n y a z ı l a n a ç ı k l a m a ’
[ ilk_deyim 1 ]
...
[ son_deyim ]
end
2.4
Veri ve Veri Yapıları
Veri, bilgisayar programında, komutlar tarafından işlenen bilgilerdir. Bu
bilgiler sayı, metin, resim, ses gibi bilgisayar girdisi (input) ya da çıktısı
(output) olurlar.
Programların çoğu birden çok veri ile işlem yapar. Birden çok veri
olduğunda onlara veri toplulukları ya da, Nesne Programlama dillerindeki
(OOP) deyimle, veri koleksiyonu (collection) diyeceğiz. Veri koleksiyonları
üzerinde farklı işlemler yapılır. O nedenle, veri koleksiyonları anabellekte,
üzerlerinde yapılacak işlemlere elverecek biçimde tasarlanmış alanlara yerleştirilir. Bu alanlara "container" denir. Veri yapısı terimi ile "container"
terimi eş anlamlıdır. Bu kitapta container yerine veri yapısı, verikabı, veri
ambarı ya da, kısaca, ambar, depo terimlerini kullanacağız. Kitap boyunca
bu terimlerin eşanlamlı olacaklarını unutmayalım.
2.5. ALGORITMA VE FONKSIYON
11
Ruby veri tipleri, verilerin depo edildiği ambarlardır. Daha açık bir
deyişle, bir veri tipi (sınıf), verilerin konulduğu depo ve bu depo üzerinde işlem yapan fonksiyonlardan oluşur. Örneğin, bir veri ambarındaki nesnelerin
sıralanması, ambar içinde bir öğenin aranması, ambara yeni öğe eklenmesi
ya da var olan bir öğenin ambardan atılması, ambarı başka bir ambara
dönüştürme gibi işleri yapan fonksiyonlar vardır.
2.5
Algoritma ve Fonksiyon
En genel anlamıyla, algoritma, bir problemi çözmek için izlenen yol, yordam
demektir; sonlu sayıda işlemlerden oluşur. Her işlem bir fonksiyondur. Sonlu
sayıda fonksiyonun bileşkesi de bir fonksiyondur. Dolayısıyla, her algoritma
bir fonksiyondur. Kavramı programcılık açısından düşünürsek, bilgisayar
algoritmaları, arka arkaya uygulanan sonlu sayıda bilgisayar komutlarıdır.
Ünlü bilgisayar bilimcisi Edsger Dijkstra der ki:
Program= Veri Yapıları + Algoritma
dır. Program, verileri istenen biçimde işlemek için algoritma kullanır. Algoritmanın verileri işleyebilmesi için, onların anabellekte işlemlere elverecek
biçimde bir yerlere konulması gerekir. Anabellekte verilerin konulduğu bu
yerlere veri yapıları (data structures) denilir.
Bugün algoritma bilim dünyasının farklı dallarında çok kullanılan
terimlerden birisidir. Matematik, bilgisayar, kriptoloji gibi dallarda özel
konuma sahiptir.
Algoritma, bir başlangıç noktasından hareketle, her biri iyi-tanımlı
sonlu sayıda ardışık komutlar (işlem) ile önceden öngörülen sonuca ulaşmak demektir. Bunu bilgisayar dilinde söylersek, girdi (input) denilen sonlu
sayıda veri, sonlu sayıda komutla işlenip çıktı (output) denilen biçime dönüşür. Girdi’yi çıktı’ya dönüştüren şey bir algoritmadır. Matematik dilinde
buna fonksiyon diyoruz. OOP dillerinde fonksiyon ve metot bazen aşanlamlı bazen küçük anlam farklarıyla kullanılır. Ruby kaynaklarında hem
fonksiyon hem metot terimleri kullanılır. Bu kitapta, çoğunlukla, metot ve
fonksiyon terimlerini eşanlamlı kullanacağız.
2.6
Veri Yapıları Üzerinde İşlemler
Her programlama dili verileri tek tek ya da topluluk olarak işleyecek araçlara sahiptir. O araçlar bilgisayar komutu, algoritma, fonksiyon, metot gibi
BÖLÜM 2. TEMEL BILGILER
12
adlar alabilir. Her şeyden önce, işlenecek verilerin veri yapısına yani verikabına yerleştirilmesi gerekir. Örneğin, tek bir tamsayı ile iş yapacaksak, o
tamsayıyı Integer tipinden bir değişkene değer olarak atarız. Böylece onu
anabellekte bir yere koymuş oluruz. Çok sayıda tamsayı ile işlem yapacaksak, onları array ya da daha uygun bir verikabına koyarız.
Verileri yerleştirmek için veri yapısını (verikabı) tasarlamak, verileri
verikabına yerleştirmek, verikabına yeni veri eklemek, verikabından veri
atmak, verikabındaki verileri sıralamak, verikabındaki verilere erişip onlar
üzerinde istenen işlemleri yapmak, verikabını başka bir verikabı tipine dönüştürmek vb. işlemler veri toplulukları üzerinde yapılan işlemlere örnektir.
Tabii, farklı veri yapıları (verikapları) üzerinde bu işleri yapan algoritmalar (fonksiyon, metot) olmalıdır. Programcı, kullandığı dilde bunları yapan
fonksiyonları (algoritma) kendisi yazabileceği gibi, hemen her dilde bu işleri
yapan fonksiyonları içeren geniş kütüphanelerden yararlanabilir. Ruby’de
gömülü metotların çoğunu Kernel modulünden alırız.
2.7
Veri Yapısı Oluşturma
Teknik açıdan veri yapısı, ana bellekte verilerin girileceği bir alandır. Veri
yapısı oluşturmak demek, ana bellekte bir alanı o yapıya tahsis etmek demektir. Nesne tabanlı bir dilde, anabellekte bir veri yapısının (verikabı)
yaratılması için, önce onun bir sınıf olarak tanımlanması ve ona ait bir
nesnenin (object) anabellekte yaratılması gerekir. Bu bağlamda, her veri
yapısının bir sınıfa karşılık geldiği görülür. Tabii, bunun tersi de doğrudur.
Her veri yapısı bir sınıftır. Başka bir deyişle,
Her veri tipi bir sınıftır, her sınıf bir veri tipidir.
Bir veri yapısını (verikabı) ötekinden ayıran şey, onun öznitelikleri ve
onlara uygulanan metotlardır.
Veri yapıları (verikabı) içerecekleri koleksiyon üzerinde yapılacak işlemleri kolaylaştıracak biçimde tasarlanır. Veriler o verikabına yerleşince,
bir bakıma o kabın işlevselliğini kazanırlar. Bir veri yapısı (verikabı) üzerinde yapılacak işlemler başka bir veri yapısı üzerinde yapılacak işlemlerden
farklıdır. Bir tek veri yapısı (verikabı) her amaca yetmez. Dolayısıyla, farklı
amaçlar için farklı veri yapıları (verikapları) oluşturulması doğaldır.
2.8. DERLENEN VE YORUMLANAN DILLER
2.8
13
Derlenen ve Yorumlanan Diller
Programlama dillerini farklı bakış açılarına göre sınıflandırmak mümkündür. Bunlardan birisi kaynak programın derlenmesini gerektiren dillerdir.
Bunlara derlenen diller denilir. Derlenen dillerin karşıtı ise, yazılan her
satırı (komut) anında makina diline çevirip çalıştıran dillerdir. Bunlara yorumlayıcı diller (interpreter) denilir. Derlenen dillerde, kodlar bir kaynak
dosyasına topluca yazılır. Sonra makinanın anlayacağı dile çevrilir (derleme,
compile). Varsa öndeden derlenmiş başka yardımcı programlarla birleştirilir (make) ve ortaya çıkan son biçim koşturulur (run). C, C++, C#, Java
gibi diller bu gruptadır.
Yorumlayıcı dillerde ise bir komut satırı yazılır ve o satır makina
diline dönüştürülür. Tek satırlık komutu alan yorumlayıcı, o satırın istediği
şeyi yapar. Basic, Perl, Python, Ruby, SQL gibi diller bu gruptandır.
Derlenen ve yorumlanan diller kendi amaçlarını gerçekleştiriler. Onlar
birbirleriyle mukayese edilemezler; dolayısıyla birini ötekine tercih etmek
olanaksızdır. Programcı yapacağı iş için kendi amacına en çok uyanı seçer.
Yormlayıcı diller, istendiğinde derlenen diller gibi de kullanılabilirler.
Başka bir deyişle, yorumlayıcı dillerde büyük programları, derlenen dillerdeki gibi çalıştırmak mümkündür Bunun için kaynak program yazılır ve
kaynak programın adı tek satırlık komut imiş gibi yorumlayıcıya verilir.
Yorumlayıcı, verilen programdaki kodları sırayla yürütür.
IDE ve GUI
Günümüzde hem derlenen hem yorumlanan programların kullanımını kolaylaştıran bütünleşik görsel arayüzler (IDE,GUI) vardır. Bunlar programcının hayatını çok kolaylaştırır.
Ruby için de bu işi yapan IDE’ler vardır; zamanla yenileri de ortaya
çıkacaktır. Bu bölümde, insanın anlayacağı dilde text olarak yazılan komutlardan başlayıp makinaya istenilen işin nasıl yaptırıldığını anlatmak istiyoruz. O nedenle IDE’lere başvurmayacağız. Her işletim sistemi için Ruby ile
gelen irb etkileşimli kabuğunu kullanacağız. Bir GUI kullanmaya alışanlar
için, başlangıçta zor gibi görünse de bu yöntemin daha öğretici olduğunu
göreceksiniz.
BÖLÜM 2. TEMEL BILGILER
14
2.9
Hatalar
Hayatta yapılacak o kadar çok hata var ki, aynı hatayı yapmakta ısrar etmenin gereği yoktur.— Jean-Paul SARTR —
Hata yapmaktan korkan insan, hiçbir şey yapamaz! — Abraham Lincoln
—
Bilgisayar programlarında üç türlü hata oluşabilir.
Sözdizimi (syntax) Hataları : Bunlar en masum hatalardır. Program
derlenemez. Dolayısıyla hiç koşmaz. Sonuç olarak, programcısından
başkasına zarar veremez. İyi derleyicilerin hemen hepsi, sözdizimi hatalarını derleme anında (compile time) bildirirler. Böylece sözdizimi
hatasının giderilmesi (debug) kolaylaşır.
Koşma Hataları (RunTime Error) : Bazı programlarda, derleyici sözdizimi hatası görmez ve programı derler. Ancak, program koşarken,
çok farklı nedenlerle koşma eylemi durabilir. Örneğin, programın koşması için gerekli olan bir çevre biriminin olmayışı (yazıcı, bir kayıt
ortamından dosya okuma, başka bir kayıt ortamına veri gönderme vb)
koşmayı durdurur. Eğer program kullanıcıya doğru uyarılar gönderiyorsa, bu tür hatalar sorun yaratmadan kullanıcı tarafından giderilir.
Bazı koşma hataları programın özüyle ilgili olabilir. Sözdizimi doğrudur; ama koşma anında gerçekleşmesi mümkün olmayan bir işlem
istenmiş olabilir. Örneğin, bir işlemde sıfıra bölme oluşuyorsa, bu hatayı derleyici farketmez; işleminin yapılamadığı, ancak koşma anında
ortaya çıkar. Programın özüne ilişkin koşma hataları, mantıksal hatalar kadar tehlikeli olmamakla birlikte, programın kaliteli olmadığının
göstergesidir.
Mantıksal Hatalar (Logical Errors) : Sözdizimi (syntax) hatası içermeyen program derlenir ve koşar. Ancak, işlemlerde mantıksal hata
olabilir. Örneğin, bir bankada faiz hesaplayan formül yanlış yazılmış
olsun. Yazılan formüle göre daha az ya da daha çok faiz hesaplanacaktır. Böyle bir hatayı derleyicinin görmesi olanaksızdır. Bu tür
hatalar, ancak dikkatli kullanıcılar tarafından farkedilebilir. Farkedilmeden programın çalışması, ileride giderilmesi çok zor sorunlar yaratır. O nedenle, mantıksal hatalar, en tehlikeli hatalardır.