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:
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.
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:
Eksiler:
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:
Eksiler: