Encapsulation Nedir ? Private Kavramı ve Getter&Setter Metotlar

Fatih İzgi
6 min readAug 14, 2021

--

Bir önceki yazımızda Constructor metotları ele almıştık ve User sınıfından nesne üretme işlemlerini gerçekleştirmiştik. Daha sonrasında bu nesnelere ait özellik ve davranışlara erişmiştik. Nesne özelliklerine erişimi ise doğrudan gerçekleştirebiliyorduk ancak bu durum OOP dünyasında uygun değildir ve tercih edilmemesi gerekir. Dolayısıyla bu yazımızda doğrudan erişimin sakıncaları ve nasıl önlemler alınabileceğinden bahsedeceğiz.

İlk yazımızda OOP kavramının “Gerçek hayatın yazılıma uyarlanması” olduğunu söylemiştik. Bu sebeple ufak bir gerçek hayat örneği vererek mantığı anlamaya çalışalım :

Bir arabaya her isteyen binemez. Arabanın kapılarını açmak ve içine binmek için anahtar kullanımı zorunludur. Böylece arabaya dışarıdan erişim engellemiş olur. Bir başka örnek olarak telefonlara konulan şifreleri düşünebiliriz. Bir telefonun şifresiz olması elbette mümkündür ancak şifresi olmayan bir telefon kullanmak gizlilik açısından iyi değildir çünkü telefonu eline alan herkes telefonda istediği işlemi yapabilir. Yazılım dünyasında da mantık aynen bu şekildedir. Ne demek istediğimizi daha ayrıntılı olarak incelemek için önceki örneğimiz üzerinden devam edelim. Hem gelen güncellemeleri görmek için hem de önceki yazıları okumayanlar için problem özeti :

Projede, bir sosyal medya uygulamasındaki kullanıcının profil sayfası üzerine kullanıcı bilgilerini yerleştirmek istiyoruz (Şimdilik bu işlemleri sadece ekrana bastırma olarak gerçekleştireceğiz. Ancak gerçekten bir web sitesi veya mobil uygulama geliştirirken de nesne kullanma mantığı örnekteki gibi olacaktır. Veri tabanından nesne verileri çekilir ve nesnelerin özellikleri ekrana yerleştirilir). Kullanıcının kullanıcı adı, yaşadığı ülke, yaş ve doğum tarihi özellikleri bulunsun. Ayrıca kullanıcı nesnesi, kendi özelliklerini gösterebileceği bir davranışa(showUserInfo() metoduna) sahip olsun.

DOĞRUDAN ERİŞİM VE SAKINCALARI

Bir sınıfta bulunan özelliklere başka sınıflardan doğrudan erişilebilmesi demek o sınıftaki özelliklerin dışarıya açık olması, yani gizlenmemiş olması demektir. Dışarıdan erişim sağlanabilmesi için özelliklerin tanımlanmasında 2 farklı durum söz konusudur :

1- Özelliklerin public olarak tanımlanması : Özelliklerin başında “public” anahtar kelimesi kullanılır.

2- Özelliklerin default olarak tanımlanması : Özelliklerin başında herhangi bir anahtar kullanılmaz.

Örneğin :

Yukarıdaki sınıf yapısında “name” değişkeni “public” anahtarı ile ve ”country” değişkeni ise herhangi bir anahtar kullanılmadan tanımlanmıştır. Bu değişkenlere başka sınıflardan doğrudan erişim sağlamak mümkündür.

İlk yazımızda OOP dünyasının bize sağladığı 4 büyük avantajdan söz etmiştik ve bu avantajlardan bir tanesinin de Bilgi Saklama(Information Hiding) avantajı olduğunu söylemiştik. İlk yazımızın bu bölümünü hatırlayalım :

Bilgi Saklama : Bir sınıfın diğer sınıflardan bağımsız olabileceğinden bahsettik. Eğer projenizde, bir sınıfın özelliklerine başka bir sınıf çok rahat bir şekilde erişebilirse ve bu özellikler üzerinde değişiklikler yapabilirse karışıklıklar ortaya çıkar ve yüksek ihtimalle hatalı sonuçlar veren bir proje geliştirmiş olursunuz. OOP felsefesi ile bu karışıklıklar önlenebilir. Bir sınıfın özellikleri gizlenebilir ve böylece dışarıdan erişime kapatılabilir. (Information Hiding)

Bilgi Saklama Avantajı’nın açıklamasından da anlayacağımız üzere nesne özelliklerine doğrudan erişim gerçekleştirmek OOP mantığına uygun olmayan bir durumdur. (Not : Elbette bazı özellikler için istisnai durumlar söz konusu olabilir.)

Peki doğrudan erişimin ne gibi sakıncaları bulunmaktadır ?

Bu durumu bir senaryo üzerinden inceleyebiliriz :

İkimiz de bir yazılım şirketinde çalışıyoruz ve bir sosyal medya uygulaması geliştiriyoruz. Ben User sınıfının tasarlanmasından sorumluyum ve siz de bu sınıftan nesne üretmekten ve diğer nesne işlemlerini gerçekleştirmekten sorumlusunuz. Bir nesneyi ürettikten sonra yaş bilgisinin güncellenmesine ihtiyaç duyuldu. Nesnenin 23 olan yaşını 24 yapacak iken yanlışlıkla “-” işaretine bastınız ve kullanıcı yaşı -24 olarak güncellendi. Oysa ki hiçbir kullanıcının yaşı negatif olamaz. Kodlama üzerinden incelemek gerekirse :

Output :

Kullanıcı Adı : Kullanıcı245

Kullanıcı Ülke : Türkiye

Kullanıcı Yaşı : -24

Doğum Tarihi : 02.06.1998

Sonuç : İkimiz de yeni bir iş aramaya başlayabiliriz.

Yazılımcının ufak bir dikkat hatası yapması sonucu programda istenmeyen sonuçlar elde edildi. Bu tarz hatalar programın çalışmaması veya yanlış çalışması gibi pek çok probleme de neden olabilir. Ayrıca büyük projelerde yüzlerce sınıf ve belki binlerce değişken bulunduğunu göz önüne alırsak isimlendirmeden dolayı ortaya çıkabilecek karışıklıklar ile de böyle bir hatanın meydana gelebileceğini tahmin edebilirsiniz.

Peki neden böyle bir problemle karşılaştık ?

Bu problemle karşılaşılma sebebi : Benim User sınıfını tasarlarken nesnenin sahip olacağı özellikleri herkese açık yapmam. Dolayısıyla da sizin bu nesne özelliklerine çok rahat bir şekilde erişebilmeniz. Bu tarz problemlerden Encapsulation sayesinde kurtulmak mümkündür.

ENCAPSULATION

Encapsulation, nesnelerin sahip olduğu özellik ve davranışların gizlenmesidir. Türkçe karşılıklarına baktığımızda Sarmalama, Kapsülleme gibi anlamlara gelir. Bu işlem “private” ve “protected” anahtarları ile gerçekleştirilir.

Not : Access Modifiers/Erişim Belirleyiciler başlığı altında bu anahtarlar çok daha ayrıntılı olarak işlenecektir. Inheritance anlatmadığımız için şimdilik sadece private üzerinden konuya devam ediyoruz.

Özellikler eğer “private” olarak tanımlanırlarsa, bu özelliklere yalnızca nesnenin üretildiği sınıf içerisinden erişim mümkün hale gelir ve diğer sınıflardan nesne özelliklerine (doğrudan) erişilemez. Böylece hata yapma riski en aza indirilmiş olur. Örneğin :

User sınıfı içerisinde nesne, int tipinde age değişkenine sahip ancak bu değişken private olarak tanımlanmış. Dolayısıyla Main içerisinde age değişkenine ulaşılmaya çalışıldığında Java hata verecektir. (java.lang.RuntimeException: Uncompilable source code — age has private access in User)

Peki nesne özelliklerine nasıl erişeceğiz ?

Nesne özelliklerini “private” olarak tanımladığımızda başka sınıflar içerisinden bu özelliklere erişimleri kısıtlamış olduk. Elbette bu durum asla nesne özelliklerine erişemeyeceğimiz anlamına gelmiyor. Tıpkı arabaya binmek için ihtiyaç duyulan anahtar veya telefonu açmak için girilmesi gereken şifre gibi biz de bir aracı yardımı ile bu özelliklere erişebiliriz. Bu noktada Getter ve Setter Metotlar yardımımıza koşuyor.

GETTER&SETTER METHODS

Getter ve Setter metotlar, kapsüllenmiş nesne özelliklerine erişmek için kullanılan metotlardır. Bu metotlar sayesinde nesne özellikleri üzerinde işlemler gerçekleştirilebilir.

Peki nasıl kullanılır ?

Getter Method : Nesnenin sahip olduğu herhangi bir değişkene erişmek için kullanılan metottur. (Erişmek derken, nesnenin özelliğine değer ataması için kullanılmaz. Var olan bir özelliği almak için kullanılır.) Return Type bulunur, yani metot int,String, ArrayList gibi bir değer döndürür. Bu sayede nesne özelliğine erişilmiş olur. Kullanımı :

public returnType getObjectAttribute(){return objectAttribute}

Not : Aslında metot isminin ne olduğu (derleyici için) önemli değildir ancak bu metot isminin “get” ile başlaması bir gelenek haline gelmiştir ve anlaşılır kod yazmak için bu şekilde isimlendirilir. Kendi örneğimiz üzerinden inceleyecek olursak :

Output :

Kullanıcı Yaşı : 23

Getter metot sayesinde nesnenin sahip olduğu age özelliğine erişilmiş oldu ve bu özellik ile işlemler(ageOfObject değişkenine atama ve ekrana bastırma) gerçekleştirilmiş oldu.

Setter Method : Nesnenin sahip olduğu herhangi bir özelliğine erişmek için kullanılan metottur. (Erişmek derken, nesnenin sahip olduğu özelliğe değer ataması yapılmak için kullanılır. Zaten var olan bir özelliği değiştirmek de mümkündür.) Return Type bulundurmaz yani metot, “void” olarak tanımlanır. Kullanımı :

public void setObjectAttribute(Type attribute){this.ObjectAttribute = attribute}

Not : Aslında metot isminin ne olduğu (derleyici için) önemli değildir ancak bu metot isminin “set” ile başlaması bir gelenek haline gelmiştir ve anlaşılır kod yazmak için bu şekilde isimlendirilir. Kendi örneğimiz üzerinden inceleyecek olursak :

Output :

user1 Yaşı : 23

user2 Yaşı : 36

Setter metot sayesinde nesnelerin özelliklerine erişilmiş oldu. user1 nesnesi oluşturulduğunda (default constructor ile oluşturulduğundan) age özelliğine herhangi bir değer atanmamıştı(Default olarak 0 değerine sahipti). Setter Method sayesinde bu özelliğe değer atanabildi. Ayrıca user2 nesnesi oluşturulurken age değişkenine değer atanmıştı ancak bu değer sonradan Setter Method sayesinde değiştirilebildi.

Peki Getter/Setter Metotlar içerisinde başka işlemler gerçekleştirmek mümkün mü ?

Elbette mümkün. Yukarıda yaşadığımız sorunu hatırlayalım. User sınıfı içerisinde int tipinde age değişkenimiz vardı ve Main içerisinde bu değişkene yanlışlıkla negatif bir değer atanmıştı. Bunu Setter içerisinde engelleyebiliriz. Örneğin :

Output :

Kullanıcı Yaşı : 18

İlk olarak kullanıcının yaşı 23 idi. Sonradan güncelleme yapılırken bir hata oluştu ve kullanıcı yaşına -24 değeri verilmeye çalışıldı ancak Setter metot içerisinde bu işleme izin verilmedi. Setter, özelliğe yeni değer atanması sırasında gelen parametreyi kontrol etti ve mümkün olmayacak bir durumu engelleyerek default olarak yaşa 18 değerini atadı. Böylece kullanıcı yaşının negatif olması gibi absürt bir durum engellenmiş oldu. Bununla beraber Getter, kendi içerisinde ekrana yazı bastırma işlemini gerçekleştirmiş oldu. Görüldüğü gibi bu metotların içini dilediğimiz gibi doldurmakta özgürüz. (Not : Elbette bu metotların içlerini kullanım amaçlarına uygun olarak doldurmakta fayda var. Gerekmediği taktirde bu metotlar içerisine kod parçaları eklemek anlaşılırlığı düşürebilir.)

PROJE

Encapsulation konusunun ayrıntılarını ve inceliklerini öğrendiğimize göre kendi projemizin tamamını incelemeye başlayabiliriz :

Output :

Kullanıcı Adı : User245

Kullanıcı Ülke : England

Kullanıcı Yaşı : 18

Kullanıcı Doğum Tarihi : 11.03.1999

--

--