25 Şubat 2023 • 25 dakikalık okuma
Nesne Yönelimli Programlama (ing: Object-oriented Programming), yazılımdaki her işlevin nesne olarak tasarlandığı programlama biçimidir. Nesne yönelimli programlama yaklaşımında, veriler ve ilişkili kodları içeren nesneler kullanılır. Nesneler sınıf (ing.: class) adlı şablonlar kullanılarak oluşturulur. Nesne içerisinde veriler özellik veya nitelik (ing.: property, attribute, field) denilen değişkenlerde, kodlar ise fonksiyon veya metot (ing.: function, method) adlı yapılar şeklinde tutulur. Bir programlama dilinin nesne yönelimli olarak sınıflandırılması için dört esası desteklemesi gerekmektedir;
Kapsülleme, nesnenin değişkenlerini ve metotlarını diğer nesnelerden saklayarak erişimi sınırlandırır ve sadece istenilen metot ve değişkenlere erişmeyi sağlayarak yanlış kullanımdan koruyan ilkedir. Amaç verilerin güvenliğini sağlamaktır. Public, Private ve Protected gibi erişim belirliyecileri ile nesne içeriğine erişim belirlenir. Açık (ing.: Public) erişim belirleyicisi ile nesne içeriğine dışarıdan erişilebilir, Gizli (ing.: Private) nesne içeriğine erişilemez. Korumalı (ing.: Protected) tanımlanmış nesne öğeleri sadece ilgili sınıfdan örneklendirilmiş nesnelerin içinden ve bu sınıfdan türetilmiş olan alt nesnelerden erişilebilir.
Kalıtım, bir sınıfın başka sınıftan özelliklerini ve metotlarını miras almasına denir. Bir sınıfın belirli özellik ve tutumlarını bir üst sınıftan alarak, kendisi için farklı olan özellikleri ayrıca uygulayabilir olmasını sağlar. Miras alınan sınıf ana (ing.: parent) sınıf, miras alan sınıf alt (ing.: sub) sınıf olarak adlandırılır. Kalıtım özelliği sayesinde birden fazla sınıfta kullanılan aynı kodların tekrar tekrar yazılması engellenir.
Soyutlama, bir nesnenin sadece başka nesneler tarafından kullanılan kısımlarının gösterilmesidir. Soyutlamanın amacı gereksiz detayların gizlenmesi ve kod karmaşıklığının azaltılmasıdır. Böylece nesnenin ana işlev ve özelliklerinin basit ve anlaşılır olmasını sağlar. Soyutlama sayesinde gizlenip soyutlanan detaylarda yazılımın geri kalanı etkilenmeden değişiklikler kolaylıkla yapılabilir.
Çok Biçimlilik, aynı sınıftan türeyen sınıflara farklı davranışlar kazandırmayı sağlar. Aynı sınıftan türeyen nesnelere aynı arayüz üzerinden erişilir olmasını sağlar ve kod tekrarını azaltır.
Nesne yönelimli programlama yaklaşımı, nesne tabanlı ve sınıf tabanlı olarak ikiye ayrılır. Sınıf tabanlı yaklaşımda; Kapsülleme, Kalıtım, Soyutlama, Çok Biçimlilik ilkelerini uygulayan diller esas alınır. Sınıf tabanlı dillerden bazılarına örnek olarak; Java, Python ve C# sayılabilir. JavaScript ise yapı olarak sınıf tabanlı değil prototip tabanlı bir dildir ve class bulunmaz prototype kullanılır. Prototype JavaScript dilinde en üst temel sınıftır. Tam olarak sınıf yapısı bulunmasa da JavaScript nesne oluşturup uygulamalarda kullanılmasını destekler. 2015 yılında JavaScript diline class anahtar kelimesi eklendi ve sınıf tanımlamak daha da kolaylaştı. Yeni eklenen özelliklerle JavaScript daha çok nesne tabanlı dillere benzese de arka tarafta hâlâ prototip tabanlı yapıyı kullanmaktadır. Özetle JavaScript, nesne yönelimli programlamayı destekleyen prototip tabanlı programlama dilidir denilebilir.
JavaScript diline EcmaScript 6 spesifikasyonuyla 2015 yılında eklenen class anahtar kelimesi ile sınıf tanımlamak oldukça kolaylaştırmıştır;
class Person {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
greet() {
return `Merhaba! Benim adım; ${this.firstName}!`;
}
}
let person = new Person("Altan", "Tekisim", 43);
console.log(person); // Person {firstName: 'Altan', lastName: 'Tekisim', age: 43}
console.log(person.greet()) // Merhaba! Benim adım; Altan!
Class içindeki bir değişken ya da fonksiyonu nesne dışından erişimini kısıtlamak için private olarak tanımlamak gerekir. Bunun için ilgili alanın başına # karakteri yazılır;
class Person {
// Private fields
#firstName;
#lastName;
#age;
constructor(firstName, lastName, age) {
this.#firstName = firstName;
this.#lastName = lastName;
this.#age = age;
}
// Public function
getFirstName() {
return this.#firstName;
}
// Public function
setFirstName(firstName) {
if(firstName) {
this.#firstName = firstName;
}
}
// Private function
#getFullName() {
return `${this.#firstName} ${this.#lastName}`;
}
// Public function
greet() {
return `Merhaba! Benim adım; ${this.#getFullName()}!`;
}
}
let person = new Person("Altan", "Tekisim", 43);
console.log(person); // Person {#getFullName: ƒ, #firstName: 'Altan', #lastName: 'Tekisim', #age: 43}
console.log(person.getFirstName()); // Altan
person.setFirstName("Tayfun")
console.log(person.greet()); // Merhaba! Benim adım; Tayfun Tekisim!
console.log(person.getFullName()); // Uncaught TypeError: person.getFullName is not a function
Kalıtım uygulamak için extends anahtar kelimesi kullanılır;
class Person {
// Private fields
#firstName;
#lastName;
#age;
constructor(firstName, lastName, age) {
this.#firstName = firstName;
this.#lastName = lastName;
this.#age = age;
}
// Public function
getFirstName() {
return this.#firstName;
}
// Public function
setFirstName(firstName) {
if(firstName) {
this.#firstName = firstName;
}
}
// Private function
#getFullName() {
return `${this.#firstName} ${this.#lastName}`;
}
// Public function
greet() {
return `Merhaba! Benim adım; ${this.#getFullName()}!`;
}
}
class Student extends Person{
// Private fields
#courses;
constructor(firstName, lastName, age, courses) {
super(firstName, lastName, age)
this.#courses = courses;
}
// Public function
getCourses() {
return this.#courses;
}
// Public function
learn() {
return `Merhaba! Benim adım; ${super.getFirstName()}! ${this.#courses} derslerini öğreniyorum.`;
}
}
let student = new Student("Altan", "Tekisim", 43, ["Matematik", "Geometri", "Etimoloji"]);
console.log(student); // Student {#getFullName: ƒ, #firstName: 'Altan', #lastName: 'Tekisim', #age: 43, #courses: Array(3)}
console.log(student.getFirstName()); // Altan
student.setFirstName("Tayfun");
console.log(student.greet()); // Merhaba! Benim adım; Tayfun Tekisim!
console.log(student.learn()); // Merhaba! Benim adım; Tayfun! Matematik,Geometri,Etimoloji derslerini öğreniyorum.
Soyutlama uygulamak için bir anahtar kelime yoktur fakat mevcut nesne tipi kontrol edilerek ve hata fırlatılarak soyutlama sağlanabilir;
class Person {
#firstName;
#lastName;
#age;
constructor(firstName, lastName, age) {
if(this.constructor == Person){
throw new Error("Object of Abstract Class cannot be created.");
}
this.#firstName = firstName;
this.#lastName = lastName;
this.#age = age;
}
// Implementation optional
getFirstName() {
return this.#firstName;
}
// Implementation required
greet() {
throw new Error("Abstract Method has no implementation.");
}
}
class Student extends Person{
// Private fields
#courses;
constructor(firstName, lastName, age, courses) {
super(firstName, lastName, age)
this.#courses = courses;
}
// Public function
getCourses() {
return this.#courses;
}
// Abstract Method optional implementation
getFirstName() {
return super.getFirstName().toUpperCase();
}
// Abstract Method implementation
greet() {
return `Merhaba! Benim adım; ${this.getFirstName()}!`;
}
// Public function
learn() {
return `Merhaba! Benim adım; ${super.getFirstName()}! ${this.#courses} derslerini öğreniyorum.`;
}
}
let student = new Student("Altan", "Tekisim", 43, ["Matematik", "Geometri", "Etimoloji"]);
console.log(student); // Student {#getFullName: ƒ, #firstName: 'Altan', #lastName: 'Tekisim', #age: 43, #courses: Array(3)}
console.log(student.getFirstName()); // ALTAN
console.log(student.greet()); // Merhaba! Benim adım; ALTAN!
let person = new Person("Altan", "Tekisim", 43); // Uncaught Error: Object of Abstract Class cannot be created.
Çok Biçimlilik uygulamak için alt sınıfta ilgili fonksiyon aynı isimde yazılır ve içeriği değiştirilir;
class Person {
// Private fields
#firstName;
#lastName;
#age;
constructor(firstName, lastName, age) {
this.#firstName = firstName;
this.#lastName = lastName;
this.#age = age;
}
// Public function
getFirstName() {
return this.#firstName;
}
// Public function
setFirstName(firstName) {
if(firstName) {
this.#firstName = firstName;
}
}
// Private function
#getFullName() {
return `${this.#firstName} ${this.#lastName}`;
}
// Public function
greet() {
return `Merhaba! Benim adım; ${this.#getFullName()}!`;
}
}
class Student extends Person{
// Private fields
#courses;
constructor(firstName, lastName, age, courses) {
super(firstName, lastName, age)
this.#courses = courses;
}
// Public function
getCourses() {
return this.#courses;
}
// Public function
learn() {
return `Merhaba! Benim adım; ${super.getFirstName()}! ${this.#courses} derslerini öğreniyorum.`;
}
// Polymorphism
greet() {
return `Merhaba! Ben; ${super.getFirstName().toUpperCase()}, Öğrenciyim!`;
}
}
let person = new Person("Aydan", "Gelmiş", 30);
let student = new Student("Altan", "Tekisim", 43, ["Matematik", "Geometri", "Etimoloji"]);
console.log(person.greet()); // Merhaba! Benim adım; Aydan Gelmiş!
console.log(student.greet()); // Merhaba! Ben; ALTAN, Öğrenciyim!