JS ILE FONKSIYONEL PROGRAMLAMA
Object Composition (Nesneleri Birleştirme Yöntemleri) — 1
Nesneleri birleştirme becerisi, bir yazılımcının en çok ihtiyaç duyduğu yeteneklerden birisidir. Bu birleştirme(composition) yöntemlerini teknikleri nelerdir ve nasıl kullanılmalıdır ?
Soyutlama ve Kapsama/Birleştime(Abstraction & Composition) konusunda daha önceden detaylı bir yazı yazmıştık. Bugün bu konunun teknik detaylarına anlamaya çalışacağız.
“Object Composition Assembling or composing objects to get more complex behavior.” ~ Gang of Four, “Design Patterns: Elements of Reusable Object-Oriented Software”
Object Composition, günümüz kompleks projelerini oluşturmak için nesneleri birleştirme veya birbirine kapsama yöntemi ile büyüterek istediğimiz projeleri oluşturuyoruz.
Burada Gang of Four “Design Patterns” kitabında üzerine basarak bahsettiği bir konuda
“Favor object composition over class inheritance.” ~ Gang of Four, “Design Patterns”.
Object-Oriented Sınıf üzerinden kalıtım yerine Object Composition yöntemimi tercih etmemizi öneriyor. Ama genelde Kalıtım mecburi gibi düşünerek her yerde bunu kullanmaya çalışıyoruz.
Bu konuda ki deneyimlerim. Domain nesnelerinde anlamlı olabilen bu yaklaşımın (yani Properties) , Behaviour paylaşımı için çok uygun olmadığı hatta bir çok zararının bulunduğu düşünüyorum. Zamanında bu sınıf hiyerarşinin oluşturduğu problemlerden dolayı ciddi refactoring yapmam gerekmişti. (Refactoring hakkında detaylı bilgi için bu Linke gidin).
Bu nedenle UI kütüphanelerinde Inheritance yerine → Composition yapılarını tercih ediyorlar. Bu konuyu daha önceki yazılardan örnekler vererek React kapsamında anlatayım.
React Composition vs Inheritance
Composition: Bileşenlerin birbirinin referanslarını tutarak onlara bir iş vermeleri veya onları kullanmaları sonucundaki ilişkidir.
Örneğin Table bileşeni Header, Rows, Columns, Sorting , Search, Pagination gibi bir sürü bileşeni içerip bunları koordineli bir şekilde çalıştırmasına deriz. React yoluda genellikle budur.
Inheritance ise React tarafından çok da tercih edilen bir yöntem değil. Hatta Class Component yerine Function component ve Hook kullanımı sayesinde Kalıtım olayına çok da gerek kalmayacaktır. Örneğin ben bir fonksiyon yazacağım renderShape() bunu bir ana sınıfa yazıp bundan türeyen Rect, Triangle sınıflarında bu renderShape kullanabilirim. Bu daha çok Java’nın kullandığı OOP gelen bir yöntemdir. JS bunu daha çok fonksiyon olarak dışarda tanımlar ve diğer sınıflardan kullanmana olanak sağlayan yöntemi tercih eder. (Not: Bu konuda daha detaylı bilgi için UI Bileşenleri Nasıl Evrimleşti yazımı okumanızı öneririm)
React Code Sharing Yöntemleri
Bu konuda önceden yazmış olduğum React Code Sharing Örnekleri yazısında Default(Code Dublication), Inheritance, HOC(High Order Component), RenderProps ve Hooks yöntemlerini denemiştik.
Eğer siz uygulama geliştirme yapınızı is-a ilişkilendirmesi ile yani ördek bir kuştur ilişkisi üzerinden yapıyorsanız bunun çok büyük sıkıntıları olacaktır. Bu ilişki kalıtım aldığı objeye çok çok sıkı bir ilişki ile bağlandığı için;
- The fragile base class problem: Kalıtım alınan ana sınıfın değişikliklere açık olması. Bu durumda bu ana sınıftan türeyen ve bunun alt sınıflarından türeyen tüm sınıfların bu değişimden etkilenecek olması.
- The gorilla/banana problem: Bu konuda Joe Armstrong Erlang Programlama dilinin tasarımcısının aşağıdaki cümlesindeki problem ortaya çıkar. Aslında siz ufak bir objeyi kullandığınızı zannederken arkaplanda bu objeyinin bağımlı olduğu bir goril hatta bir orman kadar çok nesne olabilir.
I think the lack of reusability comes in object-oriented languages, not functional languages. Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
If you have referentially transparent code, if you have pure functions — all the data comes in its input arguments and everything goes out and leave no state behind — it’s incredibly reusable You can just reuse it here, there, and everywhere.
- The duplication by necessity problem: Normalde yapısal olarak hiyerarşi sayısı arttığında yeni bir türeyen oluşturmak istediğimizde sadece bir türden türetemediğimiz 2 farklı ataya sahip olacak yapıların oluşması bu durumda da kodun dublicate edilmesi gerekecektir. Bu da bizim DRY prensibine aykırı bir durumdur.
DRY (Don’t repeat yourself): Kodunuzda farklı modülün içerisinde benzer fonksiyonalitede yapılar bulunur, bunları her modülde tekrar yazmanız kod tekrarı(code dublication) neden olacaktır. Olabildiğince belli işlerin sorumluluğunu ilgili modüllere vererek abstraction iyi sağlamak gerekiyor.
Abstraction (Soyutlama)
Tekrar kullanabilirlik için bir yapıyı soyutlamak(abstraction) gerekir. Soyutlamanın 2 temel parçası bulunur. Generalization ve Specialization
Kodun içerisinde tasarım yaparken ve yazılımı iyileştirirken sürekli bu 2 kavram üzerinden ilerleriz.
Generalization (Genelleme) : Tekrar eden örüntüleri ve işlemleri çıkarıp bu benzerlikleri bir soyutlama arkasında saklamaktır. Farz edelim tüm aldığımız ürünlerde %18 kdv ekleniyor. Tüm muhasebe yazılımı yapan uygulamaların bunu yapması yerine Bunu yapan bir fonksiyon, sınıf veya kütüphane yazarak bu muhasebe işlemini soyutlayabiliriz.
Specialization (Özelleşmek) : Özelleştirmek’te genelleştirmenin aksine sadece o duruma özel işlemleri , mantıkları oluşturarak soyutlamak anlamına gelir.
Inheritance ile Soyutlama (Abstraction)
Inheritance kullanıyorsak;
- Genelleme(Generalization) kısmını, birbirine benzeyen sınıflar için ortak arayüzlerden(interface) oluşturulmasını ve ortak fonksiyonların abstract veya ata sınıfa taşınması ile gerçekleşir
- Özelleştirme (Specialization) kısmını ise atasındakine benzemeyen davranışlar için ilgili metodu override ederek kendi davranışını oraya enjekte etmesi ile gerçekleşir.
Not: İlerleyen yazılarda Soyutlama ve (Generalization, Specialization) için tek yöntemin Inheritance olmadığını bunun yerine Object Composition faydalanabileceğimizi anlatacağım..
Referanslar
Okumaya Devam Et 😃
Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.