[Swift] 프로토콜의 확장 (Protocol Extensions)

프로토콜은 extension하여 메소드, 이니셜라이저, subscript, 연산 프로퍼티를

요구사항으로 추가할 수 있으며, 실제 동작할 수 있도록 구현도 할 수 있다.

이렇게 프로토콜을 확장하여 요구사항들을 추가하고 실제 구현하면

해당 프로토콜을 준수하는 타입에서는 따로 구현을 하지 않아도 사용할 수 있다.

protocol RandomGenerator {
    func random() -> Double
}

extension RandomGenerator {
    func randomBool() -> Bool {
        random() > 5.0
    }
}

class SomeClass: RandomGenerator {
    func random() -> Double {
        Double.random(in: 1.0 ... 10.0)
    }
}

let some = SomeClass()
some.randomBool() // true or false

위 코드에서처럼 RandomGenerator를 확장하여 randomBool 메서드를 추가하고 구현하면

RandomGenerator를 준수하는 SomeClass 타입은 randomBool 메서드를 구현하지 않아도

사용할 수 있다.

물론 준수하는 타입에서 구현하여 사용하여도 무방하다. 이 경우에는 타입에서 구현한 메서드가 사용된다.

프로토콜을 확장하여 요구사항을 추가하고, 구현할 수 있지만 다른 프로토콜을 확장, 상속할 수는 없다

protocol RandomGenerator { }
protocol AnotherProtocol { }
extension AnotherProtocol: RandomGenerator{} // 확장에서 다른 프로토콜 상속 불가

다른 프로토콜을 확장, 상속하고자 한다면 프로토콜의 선언에서 해야한다

기본 구현 (Default Implementations)

프로토콜을 확장하여 이미 프로토콜에 선언되어 있는 요구사항에 대해 구현을 하여 준수하는 타입에

제공할 수 있다. 이를 기본 구현이라고 한다

기본 구현을 제공하면 프로토콜을 준수하는 타입이 요구사항을 구현하지 않아도

기본 구현으로 제공 되기 때문에 사용할 수 있다

이 경우에도 프로토콜을 준수하는 타입에서 자체적으로 요구사항에 대해 구현을 한다면

자체 구현한 요구사항을 사용한다

protocol RandomGenerator {
    func random() -> Double
}
extension RandomGenerator {
    func random() -> Double { Double.random(in: 1.0 ... 10.0) }
}

class SomeClass: RandomGenerator { }
let some = SomeClass()
some.random()

선택적 요구사항과 기본 구현으로 제공되는 요구사항은 모두 준수하는 타입에서 자체적으로 구현을 하지 않아도 되지만, 기본 구현은 옵셔널 체인 없이 사용이 가능하다

프로토콜 확장에서의 제약조건 추가

(Adding Constraints to Protocol Extensions)

where절을 사용하여 특정 조건에서만 프로토콜이 확장되도록 선언할 수 있음

extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        for element in self {
            if element != self.first {
                return false
            }
        }
        return true
    }
}
let equalNumbers = [100, 100, 100, 100, 100]
let differentNumbers = [100, 100, 200, 100, 200]
print(equalNumbers.allEqual())
// Prints "true"
print(differentNumbers.allEqual())
// Prints "false"

이 예제의 경우 Element가 Equatable 프로토콜을 준수하는 경우에만

Collection을 확장하여 allEqual() 메서드를 사용할 수 있도록 한다

정리

  1. 프로토콜을 확장하여 요구사항을 추가하고 그 요구사항에 대해 구현을 할 수 있다
  2. 프로토콜을 확장하여 이미 선언되어 있는 요구사항에 대해 구현을 제공할 수 있고 이를 기본 구현이라고 한다
  3. 프로토콜 확장으로 요구사항이 구현되어 있다면 프로토콜을 채택한 타입에서 요구사항을 구현하지 않아도 해당 요구사항을 사용할 수 있다
  4. 요구사항을 타입에서 자체 구현하였다면 자체 구현한 요구사항이 사용된다
  5. 특정 조건을 만족하는 경우에만 프로토콜을 확장할 수 있도록 제한할 수 있다

댓글남기기