Kalıtıma Yeni Bir Bakış, “Composing Types”

Herşeyi Türkçeleştirme çabasını çok doğru bulmuyorum. Çoğu zaman yerelleştireyim derken anlamsız ifadeler türetme yoluna gidiliyor ki, bunu yapmak istemediğimden kavramları bir dönüşüme tabi tutmadan kullanmak istiyorum. Bu yüzen Tiplerin Birleşimi gibi bir çeviri yerine Composing Types kullanmak istiyorum.

Inheritance (Kalıtım) , tüm Object Oriented dillerin en temel yapılarındandır. Fakat vazgeçilmezliği yanında belirli noktalardaki kısıtlamaları ve yol açabileceği problemler sebebiyle de farklı dillerde farklı çözümler üretme çabasını görmekteyiz. “Composition” ve “Protocol Oriented” yapılara aslında bahsedeceğim bu sorunlara çözüm üretme amacıyla geliştirilen bir mimariler. Fakat gerçekten sizinde buna ihtiyaç duymanız için öncelikle problemler üzerine konuşmakta fayda görüyorum.

class Kullanici {
    var ismi: String = ""
    var yasi: Int = 0
}

class Arkadas: Kullanici {
    var tanismaTarihi: Date = Date()
}

Yukarıdaki örnek yapı üzerinden konuşalım. Arkadas sınıfı Kullanici sınıfından türetilmiş bir sınıf. Çok detaylara girmeden hemen kısıtlar üzerine konuşmak istiyorum.

    • Inheritance’ı sadece class yapıları için kullanabilirsiniz, yani referens tiplidir ve bu sebeple aslında verilerin istemediğiniz şekilde farklı nesneler ve referanslarla ilişkili hale gelmesi olasıdır. Bunu tercih etmeyeceğiniz durumlarda class yerine struct kullanmanız gerekmektedir ki, bu durumda da Inheritance kullanamayacaksınız. Alın size inheritance’a bir alternatif oluşturmanız için çok geçerli bir neden:)
    • Kullanici bilgilerini güncelleyen bir methodunuz olduğunu düşünün. Bir Kullanıcı nesnesini parametre olarak alan ve bilgilerini güncelleyen, aşağıdaki şekilde.
func guncelle(kullanici : Kullanici){
}
let arkadas = Arkadas()
guncelle(kullanici: arkadas)

Yukarıda göreceğiniz şekilde bu guncelle methoduna bir Arkadas nesnesini de parametre olarak göndermeniz mümkün. Çünkü Arkadas’ta aslında bir Kullanici. Bu da yine dikkatten kaçabilecek şekilde hataya sebep olabilecek ve debugger tarafından herhangi bir şekilde uyarılmayacağınız bir kullanım. Login olmuş kullanıcı nesnesini göndermek yerine arkadas nesnesini göndermenize kim engel olabilir ki?

“Composing Type” yaklaşımını bu durumlara çözüm olarak değerlendirmenizi tavsiye ederim. Bu yaklaşım gereği yukarıdaki iki nesneyi aşağıdaki şekilde kullanmanız gerekmektedir.

struct Kullanici {
    var ismi: String = ""
    var yasi: Int = 0
}
struct Arkadas {
    var kullanici : Kullanici
    var tanismaTarihi: Date = Date()
}

Olayı biraz Struct üzerinden değerlendirerek inheritance’a alternatif üretmiş olduk. Peki tüm veri tiplerimiz struct olmayacağına göre class yapıları için bu mantığı nasıl anlamlandırabiliriz.

Class Üzerinde “Composing Type”

UITableView nesnesini çokça kullanmışsınızdır, kullanmadıysanız öncelikle bu kısımlara bakmanızı tavsiye ederim.

Bir tableView nesnesini oluşturabilmek için UITableViewDataSource protocol’ünü implement edip aşağıdaki şekilde gerekli 2 methodu kullanmış olmanız gerekmektedir.

class ViewController: UIViewController , UITableViewDataSource{
    var list = [Arkadas]()
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        return cell!
    }
}

Burada temel sorun şudur. Başka bir tableView’i aynı şekilde Arkadas nesneleriyle doldurmak istediğiniz zaman o nesne içerisinde de yukarıdaki şekilde protocol’ü ekleyip, aynı methodları aynı şekilde eklemeniz gerekecektir. Yani aynı kodu tekrar tekrar yazmış olacaksınız.  Aslında bu MVC mimarisinin temel problemlerindendir ve MVVM benzeri mimariler buna benzer problemlere de çözümler üretmektedir. Biz şuan konuştuğumuz yaklaşımla bu soruna nasıl bir çözüm üreteceğimiz üzerinde duralım.

Öncelikle kodun tekrarına sebep olan bölüm UITableViewDatasource protokolünün implementasyonu. Bu bölümü aşağıdaki şekilde yeni bir nesne oluşturarak ayırıyorum.

class ArkadasDataSource : NSObject, UITableViewDataSource {
    var list = [Arkadas]()
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return list.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
        return cell!
    }
}

ArkadasDataSource nesnesini ihtiyacınız olan tüm nesneler içerisinde tekrara girmeden kullanabilirsiniz. Bu hem kodun tekrarının önüne geçme, hem yeniden düzenleme gerektiğinde tek bir nokta üzerinde düzenleme yapmanın kolaylığı açılarından önemlidir. Şimdi ViewController nesnemizi bu datasource sınıfını kullanacak şekilde revize edelim.

class ViewController: UIViewController{
    @IBOutlet var tableView : UITableView!
    var datasource = ArkadasDataSource()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.dataSource = datasource
        datasource.list = [Arkadas]()
        self.tableView.reloadData()
    }
}

Göreceğiniz üzere yaptığımız işlem sadece bir datasource değişkeni oluşturarak tableView.datasource olarak bu sınıfı kullanmak. Yukarıda da söylediğim gibi bu yaklaşım kodun yeniden kullanımını sağlayacak ve MVC’de yaşanılan çok fazla kod tekrarına bir çözüm olacaktır.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn
Bu yazıyı beğendiyseniz daha fazla kişiye ulaşmasını sağlamak için paylaşabilirsiniz.

Leave a reply