Protocol composition is een mechanisme in Swift waarmee je een type kunt creëren dat aan meerdere protocollen tegelijkertijd moet voldoen. Dit is een alternatieve manier om meervoudige overerving te vervangen, die er voor klassen in Swift niet is.
Achtergrond
Objective-C ondersteunde meervoudige overerving alleen voor protocollen, maar niet voor klassen. Swift bouwt voort op deze traditie door de nadruk te leggen op protocollen en hun combinaties om nieuwe abstracties te creëren.
Probleem
Programmeurs staan vaak voor de taak om een type te maken waarvan het gedrag door meerdere abstracties wordt bepaald. Meervoudige overerving leidt onvermijdelijk tot conflicten in hiërarchieën; in Swift wordt dit veilig opgelost door middel van protocollen en protocol composition.
Oplossing
In Swift kun je protocollen combineren met de operator '&'. Dit stelt je in staat om variabelen of functiedatapunten te creëren die aan meerdere protocollen tegelijk moeten voldoen.
Voorbeeldcode:
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("Rijden") } func fly() { print("Vliegen") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
Belangrijke kenmerken:
Kan je een object dat alleen één van de protocollen implementeert, doorgeven aan een parameter met protocol composition?
Nee, het object moet alle protocollen implementeren die betrokken zijn bij de composition, anders geeft de compiler een foutmelding.
Voorbeeldcode:
// struct Car: Drivable {} — kan niet worden doorgegeven aan testVehicle, aangezien fly() niet is geïmplementeerd
Werkt protocol composition met types, en niet alleen met waarden?
Protocol composition wordt toegepast op waarden (variabelen, functieparameters), maar kan niet worden gebruikt bij het definiëren van het type van een object (bijvoorbeeld, je kunt geen nieuw type declareren als een 'compositie' van protocollen — alleen een variabele).
Voorbeeldcode:
var obj: SomeProtocol & AnotherProtocol // toegestaan // typealias MyType = SomeClass & AnotherProtocol // fout
Kun je klassen en protocollen combineren met &?
Ja, maar met één beperking: slechts één klassentype (klasse of zijn afgeleid type) kan aan de linkerkant staan, de andere moeten alleen protocollen zijn, anders geeft de compiler een foutmelding.
Voorbeeldcode:
class A {} protocol B {} // func f(obj: A & B) {} // toegestaan // func f(obj: A & AnotherClass & B) {} // fout! Slechts één klassentype is toegestaan
In een project worden objecten met protocol composition gebruikt voor het doorgeven van gegevens tussen lagen, terwijl één protocol voldoende zou zijn:
func present(item: Displayable & Serializable) { ... }
Voordelen:
Gebruik van protocol composition alleen in duidelijke gevallen — bijvoorbeeld de verwerking van objecten die tegelijkertijd Codable en Identifiable ondersteunen voor algemene serialisatie:
func save<T: Codable & Identifiable>(_ item: T) { ... }
Voordelen: