2015-09-06 40 views
9

A WWDC 2015 session video, Protokol Yönelimli Programlama fikrini açıklar ve gelecekteki uygulamalarda bu tekniği benimsemek istiyorum. Bu yeni yaklaşımı anlamak için son birkaç günlüğüne Swift 2.0 ile oynuyorum ve bunu Delegate Pattern ile çalışmaya çalışmam için takıldım.Protokol Yönlendirmeli Programlama ve Temsilci Deseni

Projemin ilginç kısmının temel yapısını tanımlayan iki protokoller var (örnek kod saçma ama sorun açıklanır):

1) erişilebilir bazı bilgiler yapar bir heyet protokolü, benzer

protocol ValueProvider { 
    var value: Int { get } 
} 

2) Abo bilgilerle bir şey yapar varlığın bir arayüz protokolü: UITableViewController en dataSource protokolüne (A "Protokol-İlk" yaklaşımının fikri devreye girer burada) ettik: Veri işlemcinin gerçek uygulama ile ilgili olarak

protocol DataProcessor { 
    var provider: ValueProvider { get } 
    func process() -> Int 
} 

, şimdi çeteleler, yapılar ve sınıflar arasında seçim yapabilirsiniz. Bilgiyi nasıl işlemek istediğimin birkaç farklı soyutlama seviyesi vardır, bu nedenle sınıflar en iyi şekilde uygun görünmektedir (ancak gelecekteki kullanım durumlarında değişebileceğinden, bunu nihai bir karar vermek istemiyorum). Ben birkaç olaya özgü işlemcileri oluşturabileceği üst (yapılar ve çeteleler mümkün olmayan) üzerinde, bir taban işlemci sınıfını tanımlayabilirsiniz:

class BaseDataProcessor: DataProcessor { 
    let provider: ValueProvider 

    init(provider: ValueProvider) { 
     self.provider = provider 
    } 

    func process() -> Int { 
     return provider.value + 100 
    } 
} 

class SpecificDataProcessor: BaseDataProcessor { 
    override func process() -> Int { 
     return super.process() + 200 
    } 
} 

Yukarı her şeyin bir cazibe gibi çalışır gösteriniz. Bununla birlikte, gerçekte, belirli veri işlemcileri işlenen değerlere sıkı sıkıya bağlıdırlar (bu, değil temel işlemcinin aksine), ValueProvider'u doğrudan alt sınıfa entegre etmek istiyorum. Karşılaştırma için: genellikle, UITableViewControllers kendi dataSource ve temsilcisidir).

Önce bir varsayılan uygulama ile protokol uzantısı ekleyerek düşündüm: Ben değeri bağlı yapmak istemiyoruz BaseDataProcessor sınıfı olmasaydı

extension DataProcessor where Self: ValueProvider { 
    var provider: ValueProvider { return self } 
} 

Bu muhtemelen çalışacak. Ancak, BaseDataProcessor ve'dan gelen alt sınıflar ValueProvider'ı benimsemekte, bu uygulamayı dahili olarak geçersiz kılmaktadır, bu bir seçenek değildir.

denemelere devam etti ve bu ile sona erdi: derler ve ilk bakışta

class BaseDataProcessor: DataProcessor { 
    // Yes, that's ugly, but I need this 'var' construct so I can override it later 
    private var _provider: ValueProvider! 
    var provider: ValueProvider { return _provider } 

    func process() -> Int { 
     return provider.value + 10 
    } 
} 

class SpecificDataProcessor: BaseDataProcessor, ValueProvider { 
    let value = 1234 

    override var provider: ValueProvider { return self } 

    override func process() -> Int { 
     return super.process() + 100 
    } 
} 

istediğimi yapmama gibi görünmektedir.

weak var p: SpecificDataProcessor! 
autoreleasepool { 
    p = SpecificDataProcessor() 
    p.process() 
} 
p // <-- not nil, hence reference cycle! 

Başka bir seçenek protokol tanımlarına sınıf kısıtlamaları eklemek olabilir: bir Swift oyun alanında görülebilir bir referans döngüsü üretir Ancak, bu bir çözüm değildir. Ancak, bu benim anladığım kadarıyla POP yaklaşımını kıracaktı.

Sonuç olarak, sorumun aşağıya doğru kaydığını düşünüyorum: Protokol Yönlendirmeli Programlama ve Delege Kalıbı, protokol tasarımı sırasında kendinizi sınıf kısıtlamalarıyla sınırlamadan birlikte nasıl çalışır? Oyun alanlarında autoreleasepool kullanılarak dayanıklı referans döngüsü için uygun değildir bu

cevap

3

It turns out. Aslında, kod bir CommandLine uygulaması olarak çalıştırıldığında görüldüğü gibi, kodda bir referans döngüsü yoktur. Soru hala bunun en iyi yaklaşım olup olmadığıdır. İşe yarıyor ama biraz şahane görünüyor.

Ayrıca, ben BaseDataProcessors ve SpecificDataProcessors başlatılması pek memnun değilim. BaseDataProcessors, alt sınıfların uygulama ayrıntılarını bilmemelidir w.r.t. valueProvider ve alt sınıflar, valueProvider olma konusunda kendileri hakkında dikkatli olmalıdır. aşağıdaki gibi

Şimdilik, başlatma sorununu çözmüş: daha iyi bir fikrin varsa

class BaseDataProcessor: DataProcessor { 
    private var provider_: ValueProvider! // Not great but necessary for the 'var' construct 
    var provider: ValueProvider { return provider_ } 

    init(provider: ValueProvider!) { 
     provider_ = provider 
    } 

    func process() -> Int { 
     return provider.value + 10 
    } 
} 

class SpecificDataProcessor: BaseDataProcessor, ValueProvider { 
    override var provider: ValueProvider { return self } // provider_ is not needed any longer 

    // Hide the init method that takes a ValueProvider 
    private init(_: ValueProvider!) { 
     super.init(provider: nil) 
    } 

    // Provide a clean init method 
    init() { 
     super.init(provider: nil) 
     // I cannot set provider_ = self, because provider_ is strong. Can't make it weak either 
     // because in BaseDataProcessor it's not clear whether it is of reference or value type 
    } 

    let value = 1234 
} 

, lütfen bana bildirin :)