델리게이션
델리게이션은 코코아와 코코아 터치 프레임워크에서 광범위하게 사용된다. 델리게이션 패턴은 매우 간단하면서도 강력한 패턴으로, 어느 한 타입의 인스턴스가 다른 인스턴스를 대신해서 동작하는 상황에 잘 맞는다. 동작을 위임하는delegating 인스턴스는 델리게이트 인스턴스의 참조를 저장하고 있다가 어떠한 동작action이 발생하면 델리게이팅 인스턴스는 계획돈 함수를 수행하기 위해 델리게이트를 호출한다.
스위프트에서는 델리게이트가 해야 할 일을 정의한 프로토콜을 생성하는 방식으로 델리게이션 디자인 패턴을 구현한다. 델리게이트라 부르는 프로토콜을 따르는 타입은 해당 프로토콜을 채택하며, 프로토콜에서 정의한 기능을 제공하는 것을 보장할 것이다.
델리게이트가 해야 할 일을 정의한 프로토콜을 살펴보자.
protocol DisplayNameDelegate {
func displayName(name: String)
}
위 델리게이트 프로토콜을 준수하는 타입은 반드시 displayName 이라는 메서드를 구현해야 한다.
델리게이트를 사용하는 Person 구조체를 살펴보자.
struct Person {
var displayNameDelegate: DisplayNameDelegate
var firstName = "" {
didSet {
displayNameDelegate.displayName(name: getFullName())
}
}
var lastName = "" {
didSet {
displayNameDelegate.displayName(name: getFullName())
}
}
init(displayNameDelegate: DisplayNameDelegate) {
self.displayNameDelegate = displayNameDelegate
}
func getFullName() -> String {
"\(firstName) \(lastName)"
}
}
이 인스턴스는 firstName과 lastName 프로퍼티 값이 변경될 때 이름을 보여줘야 하는 책임을 갖게 된다.
firstName과 lastName 프로퍼티를 정의한 내부에서는 프로퍼티 옵저버property observers를
정의하고 있다. 프로퍼티 옵저버는 프로퍼티 값이 변경될 때마다 호출된다.
struct MyDisplayNameDelegate: DisplayNameDelegate {
func displayName(name: String) {
print("Name: \(name)")
}
}
위 델리게이트 타입은 콘솔에 이름을 출력한다. 위 델리게이트를 사용하는 방법은 다음과 같다.
var displayDelegate = MyDisplayNameDelegate()
var person = Person(displayNameDelegate: displayDelegate)
person.firstName = "Kim"
person.lastName = "Minsu"
이 코드는 MyDisplayNameDelegate 타입의 인스턴스를 생성하는 것으로 시작되며,
Person 타입의 인스턴스를 생성하는 데 해당 인스턴스를 사용한다.
Person 인스턴스의 프로퍼티에 값을 설정하면 콘솔에 이름을 출력하기 위해 델리게이트가 사용된다.
델리게이션 패턴은 어플리케이션 내에서 이름을 웹 서비스에 보내거나, 스크린 어딘가에 출력을 하는 것과 같이 어플리케이션이 행위를 변경하고자 할 때 그 능력이 빛을 발한다.
델리게이션 패턴을 사용함으로써 얻게 되는 또 다른 이점은 느슨한 결합Loose coupling이다. 각각의 타입이 매우 구체적인 작업에 대한 책임이 있는 경우 느슨한 결합은 책임의 분리를 촉진한다. 이는 요구 사항이 변경되는 경우 작업을 매우 쉽게 바꿀 수 있게 해준다.
위 예에서 firstName 이나 lastName 프로퍼티가 변경될 때 마다 이름을 출력하기 위해
델리게이트를 사용함으로써 코드의 로직 부분과 뷰를 분리했다.[1]
[1]> 델리게이트를 사용하여 콘솔에 출력하는 로직을 분리시켰으므로 해당 요구 사항이 변경 된 경우 > 델리게이트와 관련된 부분만 수정해도 되도록 만든다는 의미로 해석된다.