프로토콜 컴포지션은 스위프트에서 여러 프로토콜을 동시에 준수해야 하는 타입을 생성할 수 있는 메커니즘입니다. 이는 스위프트에서 클래스에 없는 다중 상속을 대체하는 대안적인 방법입니다.
문제의 역사
Objective-C는 클래스에 대해서는 다중 상속을 지원하지 않지만, 프로토콜에 대해서는 지원했습니다. 스위프트는 새로운 추상화를 구축하는 데 있어 프로토콜과 그 조합에 초점을 맞추며 이 전통을 이어갑니다.
문제
프로그래머는 종종 여러 추상화가 정의하는 동작을 가진 타입을 만들어야 합니다. 다중 상속은 계층 간의 충돌을 불가피하게 일으키며, 스위프트에서는 프로토콜과 프로토콜 컴포지션을 통해 안전하게 해결됩니다.
해결책
스위프트에서는 '&' 연산자를 사용하여 프로토콜을 조합할 수 있습니다. 이는 동시에 여러 프로토콜을 준수해야 하는 변수나 함수 매개 변수를 생성할 수 있게 합니다.
코드 예제:
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("Driving") } func fly() { print("Flying") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
주요 특징:
프로토콜 컴포지션 매개 변수로 하나의 프로토콜만 구현한 객체를 전달할 수 있나요?
아니요, 객체는 컴포지션에 참여하는 모든 프로토콜을 구현해야 하며, 그렇지 않으면 컴파일러가 오류를 발생시킵니다.
코드 예제:
// struct Car: Drivable {} — testVehicle에 전달할 수 없습니다, 왜냐하면 fly()가 구현되지 않았기 때문입니다.
프로토콜 컴포지션이 값이 아닌 타입にも 적용되나요?
프로토콜 컴포지션은 값(변수, 함수 매개 변수)에 적용되지만 객체의 타입 정의에는 사용되지 않습니다 (예: 새로운 타입을 어떤 "프로토콜의 조합"으로 선언할 수 없습니다 — 변수에 대해서만 가능합니다).
코드 예제:
var obj: SomeProtocol & AnotherProtocol // 가능 // typealias MyType = SomeClass & AnotherProtocol // 오류
&를 사용하여 클래스와 프로토콜을 조합할 수 있나요?
네, 그러나 한 가지 제한이 있습니다: 왼쪽에는 하나의 클래스 타입(클래스 또는 그 자식 클래스)만 올 수 있으며, 나머지는 모두 프로토콜이어야 합니다. 그렇지 않으면 컴파일러가 오류를 발생시킵니다.
코드 예제:
class A {} protocol B {} // func f(obj: A & B) {} // 가능 // func f(obj: A & AnotherClass & B) {} // 오류! 하나의 클래스 타입만 허용됩니다.
프로젝트에서 층 간 데이터를 전송하기 위해 프로토콜 컴포지션을 사용하는 객체를 사용했지만, 하나의 프로토콜만으로도 충분했습니다:
func present(item: Displayable & Serializable) { ... }
장점:
명백한 경우에만 프로토콜 컴포지션을 사용하는 것 — 예를 들어, 일반화된 직렬화를 위해 Codable과 Identifiable을 동시에 지원하는 객체 처리:
func save<T: Codable & Identifiable>(_ item: T) { ... }
장점: