스위프트에서는 **프로토콜 지향 프로그래밍 (POP)**에 큰 비중을 두고 있습니다. POP의 기본 아이디어는 기본 클래스가 아닌 프로토콜(인터페이스)부터 아키텍처를 설계하는 것입니다. 프로토콜은 여러 체인을 통해 행동을 상속받을 수 있는 유연성을 제공하며, 코드의 결합도를 낮춥니다.
스위프트는 프로토콜이 default 구현(확장을 통해)을 가질 수 있도록 하여 클래스 계층 구조 없이도 코드 재사용을 촉진합니다. 전통적인 OOP는 클래스 간의 상속에 의존하며, 이는 단일 상속 체인으로 제한됩니다. POP는 이러한 제한이 없으며, 구성 및 확장성을 허용합니다.
코드 예제:
protocol Drivable { func drive() } extension Drivable { func drive() { print("Driving forward!") } } struct Car: Drivable {} let car = Car() car.drive() // 출력: Driving forward!
프로토콜 확장에 저장 속성(stored property)을 추가할 수 있을까요?
답변: 아닙니다, 프로토콜의 확장에는 저장 속성(stored property)을 추가할 수 없고, 오직 계산된(computed) 속성과 메서드만 추가할 수 있습니다. 예를 들어,
// 오류! extension Drivable { var speed: Int = 0 // 컴파일 오류: Extensions may not contain stored properties }
이야기
대규모 프로젝트에서 개발자들은 상태 추적을 위해 프로토콜 확장을 통해 저장 속성을 추가하려고 했습니다. 코드가 오류와 함께 컴파일되어 스프린트 중에 아키텍처를 긴급히 재설계해야 했으며, objc_get/setAssociatedObject와 같은 외부 솔루션을 사용하게 되어 코드 가독성이 떨어졌습니다.
이야기
프로젝트에서는 다양한 엔티티 유형을 위한 기본 클래스를 구현하고 프로토콜을 통해 다중 상속을 사용했습니다. 개발자는 확장의 기본 구현 동작을 혼동하여 struct에서 이 메서드를 재정의하려고 했으며, 결과적으로 struct에서의 구현이 호출될 것이라고 예상했습니다. 결국 메서드 호출 순서를 추적하기 어려웠습니다.
이야기
모듈을 확장하는 과정에서 책임 분리를 위해 프로토콜을 사용했으나, POP에 대한 경험 부족으로 인해 프로토콜 간의 명확한 종속성을 보장하지 않았습니다. 이로 인해 코드 중복이 발생하고 대규모 개발 팀에서 여러 확장을 병합할 때 인터페이스 충돌이 발생했습니다.