ProgramlamaSwift orta seviye geliştirici

Swift'te protokol bileşimi nedir, nasıl çalışır ve ne için gereklidir? Birden fazla protokolü aynı anda kullanırken dikkate alınması gereken noktalar nelerdir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Swift'te birçok OOP dilinin deneyimleri, protokolleri sadece miras almanın yanı sıra birleştirme (bileşime) imkanı ile genelleştirilmiş ve geliştirilmiştir. Protokol bileşimi, bir değişken, işlev parametresi veya generic'in birden fazla protokole uymasını gerektiren bir biçimde tanımlanmasına olanak tanır. Bu mekanizma, birden fazla sözleşme (interface) davranışına sahip nesnelerle çalışmak gerektiğinde son derece kullanışlıdır ve çoklu mirasın dezavantajlarını esnek bir şekilde aşmayı sağlar. Bileşimin çözdüğü sorun, "nesne bir grup gereksinimi karşılamalıdır" ifadesini tek bir gereksinimin ötesine taşımaktır.

Swift'teki çözümde özel bir sözdizimi kullanılır: protokollerin birleştirilmesi '&' (ampersand) işareti ile yapılır, örneğin protocolA & protocolB. Arkada, runtime kontrolü (örneğin, tür dönüştürmeleri ve generic bağlamlarda dönüştürmeler) gerçekleştirilir. Bu, türlerin sayısını minimize eder ve "sorumlulukların ayrılması" modelini esnek bir şekilde gerçekleştirir.

Kod örneği:

protocol Drawable { func draw() } protocol Movable { func move() } struct Sprite: Drawable, Movable { func draw() { print("Sprite çizilir") } func move() { print("Sprite hareket eder") } } func animate(object: Drawable & Movable) { object.draw() object.move() } let s = Sprite() animate(object: s)

Anahtar özellikler:

  • Mirasa dayalı hiyerarşiler olmadan davranış bileşimini esnek bir şekilde ifade etmeyi sağlar
  • Tüm sözleşmelerin aynı anda yerine getirilmesini garanti eder
  • Generic parametreler ve type alias ile uyumludur

Soru ve Cevaplar.

protocolA & protocolB türünde bir değişken oluşturulabilir mi, belirli bir yapı ya da sınıfa bağlı olmadan?

Evet, bir değişkeni birden fazla protokole uygun olarak tanımlamak mümkündür, örneğin:

var obj: protocolA & protocolB

Ancak önemli bir not: böyle değişkenler, eğer bileşimde en az bir protokol sınıf türleri ile kısıtlıysa (protocol: AnyObject) sadece nesnelere (value-typelere değil) referans verebilir.

Bileşime bir sınıf türü (örneğin, SomeClass & Drawable) dahil edilebilir mi?

Evet, ama bazı nüanslarla: SomeClass & Protocol türünde bir bileşim, değerlerin mutlaka bu sınıfın (veya miras alanlarının) örnekleri olması gerektiğini gerektirir; böyle bir yaklaşım generic türlerin sınırlandırılması için uygulanır.

Protokol uzantısında associated type olarak protokol bileşimi kullanabilir miyiz?

Evet, ancak kısıtlamalar vardır: associatedtype olarak bir bileşim tanımlanamaz, ancak extension'da protokol bileşimlerinin kısıtlanması için where kullanmak mümkündür; örneğin, birden fazla protokole uygun türlerle sınırlı bir extension.

Tipik Hatalar ve Anti-Desenler

  • Sekiz-dokuz protokolle bileşimin kullanılması: bu mimarinin aşırı yüklenme belirtisidir ve kötü sorumluluk paylaşımının göstergesidir.
  • Value-type'ı (struct) AnyObject kısıtlaması ile protokol bileşimi değişkenine dönüştürmek her zaman hata verir.
  • Uygulamanın farklı yerlerinde aynı bileşimi kullanmamak: okunabilirliği zorlaştırır.

Hayattan Örnek

Negatif Vakıa

Projede 5 benzer protokol tanımlanmış — Drawable, Movable, Resizable, Colorable, Animatable. Her yerde Drawable & Movable & Resizable & Colorable & Animatable bileşimi uygulanmıştır. Tipik hatalar, bazı varlıkların sözleşmelerden birini gerçekleştirmemesinden dolayı karmaşık hatalarla sonuçlanmıştır.

Artılar:

  • Derin miras gerektirmez
  • Fonksiyonelliği eklemek veya kaldırmak kolaydır

Eksiler:

  • Uygunsuzlukları takip etmek zordur
  • Karmaşık testler
  • Beyanların kötü okunabilirliği

Pozitif Vakıa

Karmaşık bileşim yerine iki ana protokol (örneğin, Actor ve Viewable) belirlenmiş, "DynamicEntity" bileşimi için typealias yapılmış ve her yerde kullanılmıştır. Sorumluluk alanları net bir şekilde ayrılmıştır.

Artılar:

  • Kod okunabilirliği ve bakımı daha kolaydır
  • Testler, DynamicEntity için davranışları net bir şekilde ortaya koyar
  • Gereksinimlerin listesini hızlı bir şekilde değiştirme imkanı sağlar

Eksiler:

  • Mimariyi yeniden düşünmeyi gerektirir
  • Bazen mevcut sınıfları gereksinimlere uydurmak için bölmek gerekebilir.