Nesne yönelimli programlama (NYP) | Object Oriented Programming (OOP)
Nedir?
Her işlevin nesneler olarak soyutlandığı bir programlama yaklaşımıdır. NYP destekleyen programlama dilleri yüksek seviye diller olarak adlandırılır. En yaygın NYP dillerinden bazıları, Python, C++, Objective-C, Smalltalk, Delphi, Java, Swift, C#, Perl, Ruby ve PHP’ dir.

Bu yazıda kavramları gerçekleştirmek için Python dilini kullanacağız.
OOP teorisinde 4 temel özelliğin gerçekleştirilmesi zorunlu sayılmıştır ve biri bile eksik ise bu dil saf OOP sayılmamıştır. Bunlar:
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
Temel Kavramlar
Nesne (Object) ve Sınıf (Class) Nedir?
Sınıflardan üretilen her değişkene nesne adı verilir. Sınıf nesnelerin özelliklerini(attribute) ve davranışlarını(method) saklayan yapılardır.
Sınıf class anahtar kelimesi ile tanımlanır.
In [1]:
class Square: # Sınıf class anahtar kelimesi ile tanımlanır.
pass # Sınıfın içeriğini daha sonra tanımlamak için kullanılır.
In [2]:
square = Square()
square # object(nesne)
Out[2]:
<__main__.Square at 0x7f1fa8776410>
Nitelikler / Attribute
class class_name:
attribute1
attribute2
In [3]:
class Square:
edge = 5 # attribute
In [4]:
square = Square()
square.edge # özelikklere erişmek
Out[4]:
5
In [5]:
square.edge = 7 # özelliğe yeni değer atanması.
#Özelliğin bu şekilde değiştirlmesi nesne yönelimli programa uygun düşmez.
#Bunun engellenmesi gerekir.
square.edge
Out[5]:
7
Metotlar / Methods
class class_name:
attribute1
def method_name:
In [6]:
class Square():
edge = 5
area = 0
def area_calculate(self):
# self sınıfın özelliklerine erişmemizi sağlar. Belirtilmediği durumda hata verir.
self.area = self.edge * self.edge
print("Area =", self.area)
In [7]:
square = Square()
print(square.edge)
print(square.area)
square.area_calculate()5
0
Area = 25
Fonksiyon ve metot arasındaki fark
Fonksiyonlar sınıflar dışında tanımlanır, metotlar ise sınıfların içinde tanımlanır ve self parametresini alır.
In [8]:
def area_calculate_function(edge): # Fonksiyon, sınıftan bağımsız çalışır.
area = edge * edge
print("Area =", area)
In [9]:
area_calculate_function(7)Area = 49
Eğer fonksiyon ile hesaplanan değeri farklı bir işlemde kullanmamız gerekiyorsa return ile hesaplan değeri dışarı aktarabiliriz.
In [10]:
def area_calculate_function(edge):
area = edge * edge
print("Area =", area)
return area
In [11]:
area = area_calculate_function(6)
print(area)Area = 36
36
Yapılandırcı / Initializer or Constructor
Yapılandırıcıların (constructor) görevi oluşturulan nesneyi ilk kullanıma hazırlamasıdır. Python’da init anahtar kelimesi ile initializer tanımlanır.
In [12]:
class Animals(object):
def __init__(self, name, age):
self.name = name
self.age = age
def getAge(self):
return self.age
def getName(self):
print(self.name)
In [13]:
animal1 = Animals('dog', 2)
animal2 = Animals('cat', 5)
In [14]:
print("Animal-1 Info: ", animal1.name, animal1.age)
print("Animal-2 Info: ", animal2.name, animal2.age)Animal-1 Info: dog 2
Animal-2 Info: cat 5
Dört Temel Özelliğin
- Encapsulation
- Inheritance
- Polymorphism
- Abstraction
1.Kapsülleme / Encapsulation
Nesne yönelimli programlamanın ilk prensibi kapsülleme (encapsulation) olarak adlandırılır. Bu özellik, dilin nesne kullanıcısından gereksiz uygulama ayrıntılarını saklar. Oluşturulan bir sınıf (class) içerisinde kullanıcının işlemlerini daha kolay gerçekleştirebilmesi için bazı işlemler birleştirilerek tek bir işlem gibi gösterilir. Bu birleştirme işlemine kapsülleme denir.
Erişim belirteçleri (access modifier) sayesinde kapsülleme çok daha kolay yapılmaktadır. Erişim belirteçleri, oluşturulan sınıf veya sınıf içindeki elemanların erişim seviyelerini belirlemek için kullanılan anahtar kelimeler grubuna verilen isimdir. Metotlar ve değişkenler bir anahtar sözcük ile önceden bellirlenen sınırlar dahilinde kullanılabilir. Bu anahtar kelimeler şu şekilde sıralanabilir.
- public(global): Sistemdeki bütün sınıfların erişebilmesini sağlar. Yalnızca aynı proje içinden değil, diğer projelerden de erişim sağlanabilir.
- private: Bir “özellik (property)”in veya “metod”un sadece tanımlandığı sınıftan erişilebilmesini sağlar.
- protected: Sadece tanımlandığı sınıfın içinde ve o sınıftan türetilmiş diğer sınıfların içinde erişilebilir.
Python’da nesneye erişim kısıtlaması koymak için değişkenin ismin başına __ işareti eklenir. Belirtilmediği durumda değişken global olarak kabul edilir.
In [15]:
class BankAccount():
def __init__(self, name, money):
self.name = name #public
self.__money = money #private
In [16]:
ali = BankAccount("Ali", 2000)
ali.name
Out[16]:
'Ali'
In [17]:
ali.money---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-35412f66a497> in <module>
----> 1 ali.moneyAttributeError: 'BankAccount' object has no attribute 'money'
In [18]:
# Private özelliklere erişmek için get ve set fonksiyonları kullanılır.
class BankAccount():
def __init__(self, name, money):
self.name = name
self.__money = money
def getMoney(self): # Değişkene ulaşmak için kullanılır.
return self.__money
def setMoney(self, amount): # Değişkene değer ataması için kulllanılır.
self.__money = amount
def increase(self):
self.__money = self.__money + 100
In [19]:
veli = BankAccount('veli', 4000)
veli.getMoney()
Out[19]:
4000
In [20]:
veli.setMoney(4500)
veli.getMoney()
Out[20]:
4500
Private methods
In [21]:
veli.increase()
veli.getMoney()
Out[21]:
4600
In [22]:
class BankAccount():
def __init__(self, name, money):
self.name = name
self.__money = money
def getMoney(self):
return self.__money
def setMoney(self, amount):
self.__money = amount
#private method
def __increase(self):
self.__money = self.__money + 100
In [23]:
oya = BankAccount('Oya', 3000)
oya.increase()---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-23-e5147198dadb> in <module>
1 oya = BankAccount('Oya', 3000)
----> 2 oya.increase()AttributeError: 'BankAccount' object has no attribute 'increase'
2.Miras / Inheritance
Nesne Yönelimli Programlama (Object Oriented Programming) dillerindeki ana prensiplerinden biri Miras(Inheritance) kavramıdır. Bir sınıfın özelliklerinin ve metotlarının başka sınıflara aktarılarak işlevinin artırılmasını sağlar. Oluşturulan ve genel özellikler içeren ilk sınıfa temel sınıf (parent class), ondan miras alınarak özelleştirilen alt sınıflara türetilmiş sınıflar (child class) denir. Miras kavramı, birbirlerine benzeyen sınıfları tek tek yazmak yerine, ortak üyeleri belirleyerek bir temel sınıf oluşturmak ve geri kalanlarını bu sınıftan türetmek gibi pratik bir yol sunar.
In [24]:
# parent
class Animals:
def __init__(self):
print("animal is created")
def toString(self):
print("animal")
def walk(self):
print("animal walk")
In [25]:
# child
class Monkey(Animals):
def __init__(self):
super().__init__() # Temel(ana) sınıfın __init__ metotunu kullandığını belirmek için kullanılır.
print("monkey is created")
def toString(self):
print("monkey")
# extend
def climb(self):
print("monkey can climb")
In [26]:
monkey = Monkey() # Animal sınıfının __init__ metotunu kullandıanimal is created
monkey is created
In [27]:
monkey.toString()monkey
In [28]:
monkey.walk()animal walk
In [29]:
monkey.climb()monkey can climb
In [30]:
# child
class Brid(Animals):
def __init__(self):
Animals.__init__(self) # super yerine bu şekilde de kullanılabilir.
print("bird is created")
def toString(self):
super().toString() # Temel(ana) sınıfın herhangi metotunu için de kullanılabilir.
print("bird")
# extend
def fly(self):
("bird can climb")
In [31]:
bird = Brid()
bird.toString()animal is created
bird is created
animal
bird
In [32]:
bird.climb() # clibm sadeve Monkey sınıfına ait olduğu için erişilemez.---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-32-d727ce9a6312> in <module>
----> 1 bird.climb() # clibm sadeve Monkey sınıfına ait olduğu için erişilemez.AttributeError: 'Brid' object has no attribute 'climb'
3.Soyut Sınıflar / Abstract Classes
Nesne tabanlı programlamada sınıf hiyerarşisi oluşturulurken, bazen en tepede bulunan sınıf türünden nesneler programcılar için anlamlı olmayabilir. Hiyerarşinin en tepesinde bulunan sınıfın kendisinden türetilecek olan alt sınıflar için ortak bir arayüz (interface) görevi yapması istenebilir. Bunun için çözüm olarak oluşturulan metotlara ve sınıflara soyut metot (abstract method) ya da soyut sınıf (abstract class) denir. Soyut sınıflar büyük projelerde kullanılırlar ve kalıtım özelliğini kullanarak kod tekrarını azaltırlar. Soyut sınıflar diğer sınıflara taban olmak için kullanılırlar. Nesne türetemezler. Önlerine “abstract” sözcüğü yazılarak soyutlaştırılırlar. Önlerine “virtual” yazılmaz çünkü “abstract” sözcüğü uygulanan tüm sınıf ve metotlar zaten sanaldır.
Kullanırken dikkat edilmesi gerekenler:
Soyut sınıflar “abstract” türünden nesneler tanımlamazlar.
In [33]:
from abc import ABC, abstractclassmethod
class Animals(ABC): # Abstract Base Class (ABC) -> Soyut sınıf olduğunu belirtmek için miras alınır.
@abstractclassmethod # metodun soyut olduğunu belirmek için kullanılır.
def walk(self):
pass
@abstractclassmethod
def run(self):
passanimal = Animals() # Soyut sınıf olduğu için nesne üretemedik.---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-33-f11658647595> in <module>
8 pass
9
---> 10 animal = Animals() # Soyut sınıf olduğu için nesne üretemedik.TypeError: Can't instantiate abstract class Animals with abstract methods run, walk
Soyut metotlar override edilmek zorundadırlar, aksi takdirde derleyici hatası alınır.
In [34]:
class Bird(Animals):
def __init__(self):
print("bird")
bird = Bird()
# Soyut sınıftan miras aldığı için soyut sınıfta tanımlanan metotların
# burada tanımlanması gerekir tanımlanmadığı durumda hata dönderir.---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-34-04fd352055b6> in <module>
3 print("bird")
4
----> 5 bird = Bird()
6 # Soyut sınıftan miras aldığı için soyut sınıfta tanımlanan metotların
7 # burada tanımlanması gerekir tanımlanmadığı durumda hata dönderir.TypeError: Can't instantiate abstract class Bird with abstract methods run, walk
In [35]:
class Bird(Animals):
def __init__(self):
print("bird")
def walk(self):
print("walk")
def run(self):
print("run")
bird = Bird()bird
Soyut sınıflar içerilerinde soyut olmayan metotlar da barındırabilir ancak soyut metotlar sadece soyut sınıflar içerisinde bildirilebilir.
In [36]:
class Bird(Animals):
def __init__(self):
print("bird")
def walk(self):
print("walk")
def run(self):
print("run")
@abstractclassmethod
def fly(self):
print("fly")
bird = Bird()---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-36-ee4be90cc5b4> in <module>
10 print("fly")
11
---> 12 bird = Bird()TypeError: Can't instantiate abstract class Bird with abstract methods fly
Soyut sınıf ve arayüz arasındaki farklar ve benzerlikler:
- Arayüz içerisindeki tüm öğelerin “public” olması gerekirken soyut sınıflarda tüm öğelerin “public” olması zorunlu değildir.
- Bir sınıf sadece bir soyut sınıftan miras olarak tanımlanabilir ancak birçok arayüz tarafından bildirilebilir.
- Soyut sınıf ve arayüz için yazılacak olan soyut metotların gövdeleri bulunmaz.
- Soyut sınıflar çoklu ortamı desteklemezler ancak arayüz destekler.
- Soyut sınıflar kullanım hızı açısından arayüzden daha avantajlıdır.
- Soyut bir sınıfın tüm metotları soyut yapılırsa arayüz olarak kullanılabilir.
- Geçersiz Kılmak / Overriding
Nesne Yönelimli (Object Oriented) Programlama’da, ana sınıftaki bazı metodlara, o sınıftan türetilen yeni sınıflarda ihtiyaç duyulmayabilir ya da bu metodlar üzerinde değişiklikler yapılması gerekebilir. Bu durum genellikle yazılan kodun, bir temel sınıf ve bu sınıftan türetilmiş farklı sınıfları etkileyeceği zamanlarda ortaya çıkar ve Overriding (geçersiz kılma) kullanılarak çözülebilir.
In [37]:
#parent
class Animals:
def toString(self):
print("animal")
#child
class Monkey(Animals):
def toString(self):
print("monkey")
In [38]:
animal = Animals()
animal.toString()animal
In [39]:
monkey = Monkey()
monkey.toString()monkey
4.Çok Biçimlilik / Polymorphism
Polymorphism (çok biçimlilik) nesne yönelimli programlamada programlama dilinin farklı tip verileri ve sınıfları farklı şekilde işleme yeteneğini belirten özelliğidir. Daha belirgin olmak gerekirse, metotları ve türetilmiş sınıfları yeniden tanımlama yeteneğidir
In [40]:
class Employee:
def raisee(self):
raise_rate = 0.1
return 100 + 100 * raise_rate
class EEE(Employee):
def raisee(self):
raise_rate = 0.2
return 100 + 100 * raise_rate
class CE(Employee):
def raisee(self):
raise_rate = 0.3
return 100 + 100 * raise_rate
In [41]:
emp = Employee()
ce = CE()
eee = EEE()
In [42]:
emp.raisee()
Out[42]:
110.0
In [43]:
eee.raisee()
Out[43]:
120.0
In [44]:
ce.raisee()
Out[44]:
130.0
Kaynaklar
- https://bidb.itu.edu.tr/seyir-defteri/blog/2019/02/05/object-oriented-programming#:~:text=Polymorphism%20(%C3%A7ok%20bi%C3%A7imlilik)%20NYP',t%C3%BCretilmi%C5%9F%20s%C4%B1n%C4%B1flar%C4%B1%20yeniden%20tan%C4%B1mlama%20yetene%C4%9Fidir.
- https://www.udemy.com/course/python-nesne-tabanli-programlama/
- https://tr.wikipedia.org/wiki/Nesne_y%C3%B6nelimli_programlama