[iOS ] Delegate 디자인 패턴 - The Delegate Design Pattern

LeeEunJae·2023년 3월 20일
0

iOS

목록 보기
11/14

💁‍♂️ Delegate 패턴

Delegate 패턴은 iOS 에서 자주 사용되는 유명한 디자인 패턴이다.
Delegate 를 직역하면 (권한, 업무를)위임하다 라는 뜻을 가지고 있다. 여기서는 피위임자(위임을 받는자)라고 생각하는게 편할 것 같다.

Delegate 패턴을 말로 풀어서 설명을 하면, A라는 객체는 delegate(피위임자)라는 속성을 가지고 있고, B가 그 위임자 역할을 함으로써, A의 일을 B가 위임해서 하는 것이다.
글로만 봤을 때는 이해가 안되는게 당연하다.

백문이불여일견 일단 예제 코드를 진행하면서 하나씩 알아보자

👨‍💻 Emergency Situation

이해를 돕기 위해 비유를 사용하겠습니다.
응급 콜센터의 경우 콜센터 직원은 응급 전화가 오면, 출동이 필요할 때, 인력을 파견하는 것이 그의 임무입니다.
현장에 출동한 인력은 응급환자에게 PCR 을 수행하거나 적절한 조치를 취해야 합니다.
또 다른 인력은 응급환자에게 적절한 다른 조치를 취할 수도 있겠죠.

이러한 흐름들을 코드로 구현해보겠습니다.

protocol AdvancedLifeSupport {
    func performCPR()
}

AdvancedLiveSupport 프로토콜에는 현장에 출동한 인력이 수행할 적절한 조치에 대해서 정의합니다.

class EmergencyCallHandler {
    var delegate: AdvancedLifeSupport?
    
    func assessSituation() {
        print("Can you tell me what happened?")
    }
    
    func medicalEmergency() {
        delegate?.performCPR()
    }
}

EmergencyCallHandler 는 응급콜센터 직원 입니다.
응급 전화가 오면, 현장에 출동할 인력 즉, 피위임자인 delegate 를 속성으로 갖습니다.
이 속성의 타입은 위에서 만든 프로토콜 입니다. 따라서 피위임자는 환자에게 CPR 을 수행할 수 있겠죠.

struct Nurse: AdvancedLifeSupport {
    
    init(handler: EmergencyCallHandler) {
        handler.delegate = self
    }
    
    func performCPR() {
        print("The paramedic does chest compressions, 30 per second.")
    }
}

nurse 는 간호사이고, AdvancedLiveSupport 프로토콜을 따르기 때문에 어떻게 CPR 을 하는지 알고 있습니다.
여기서 중요한 것은 생성자 입니다.

init(handler: EmergencyCallHandler) {
        handler.delegate = self
}

간호사 객체가 생성될 때, 응급콜센터 직원이 유기적으로 연결되어 있습니다.

생성자 파라미터로 EmergencyCallHandler 를 받고, 그의 피위임자는 self 로 지정하면서 nurse 가 됩니다.

class Doctor: AdvancedLifeSupport {
    
    init(handler: EmergencyCallHandler) {
        handler.delegate = self
    }
    func performCPR() {
        print("The doctor does chest compressions, 30 per second.")
    }
    
    func useStethescope() {
        print("Listening for heart sounds")
    }
}

또다른 피위임자 역할을 할 Doctor 입니다.

let suzy = EmergencyCallHandler()
let eunjae = Nurse(handler: suzy)
suzy.assessSituation() // Can you tell me what happened?
suzy.medicalEmergency() // The Nurse does chest compressions, 30 per second.
let park = Doctor(handler: suzy) 
suzy.assessSituation() // Can you tell me what happened?
suzy.medicalEmergency() // The doctor does chest compressions, 30 per second.

자 이제 객체를 생성해서 코드를 실행해봅시다.
실행 결과는 주석에 달아놓은것과 같습니다.

위의 코드를 말로 풀어서 설명해보겠습니다.

suzy는 응급 콜센터 직원입니다.
eunjae는 간호사이고, 응급 콜센터 직원인 suzy로부터 응급상황 전달을 대기중입니다.
suzy가 응급 전화를 받았습니다.
suzy가 현재 피위임자(간호사)에게 응급상황을 전파하고, 피위임자(간호사)는 현장에 출동해 CPR을 수행합니다.

park는 의사이고, 응급 콜센터 직원인 suzy로부터 응급상황 전달을 대기중입니다.
suzy가 응급 전화를 받았습니다.
suzy가 현재 피위임자(의사)에게 응급상황을 전파하고, 피위임자(의사)는 현장에 출동해 CPR을 수행합니다.

📌 Delegate 패턴을 iOS 개발에 적용

응급상황발생 버튼을 누르면 가운데 Lable의 텍스트를 변경시키는 간단한 예제입니다.
protocol AdvancedLifeSupport {
    func performCPR()
}

struct EmergencyCallHandler {
    var delegate: AdvancedLifeSupport?
        
    func medicalEmergency() {
        self.delegate?.performCPR()
    }
}

먼저 프로토콜을 정의하고, delegate 속성을 갖는 응급콜센터직원 구조체를 만듭니다.

class ViewController: UIViewController {
    @IBOutlet weak var emergencyLabel: UILabel!
    var emergencyCallHandler = EmergencyCallHandler()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        emergencyCallHandler.delegate = self
    }

    @IBAction func occurEmergency(_ sender: UIButton) {
        emergencyCallHandler.medicalEmergency()
    }
    
}

//MARK: - AdvancedLiveSupport

extension ViewController: AdvancedLifeSupport {
    func performCPR() {
        emergencyLabel.text = "30초간 CPR을 진행 합니다."
    }
}

View와 연결되어 있는 ViewController에서 EmergencyCallHandler 를 정의하고, delegate(피위임자)로 자기자신(self)인 ViewController로 설정합니다.
Delegate 패턴으로 인해 버튼 클릭시 medicalEmergency() 를 호출하면 밑에서 구현한 performCPR을 수행하게 됩니다.

위와 같이 Swift Extension을 활용해서 코드를 분리하면, 좀 더 깔끔하게 코드를 작성할 수 있습니다.

👨‍💻 마치며..

Delegate 패턴은 왜 사용하는걸까? 여러가지 이유가 있겠지만, 내가 생각하기에는 이렇다.
AdvancedLiveSupport 프로토콜에는 performCPR()을 정의만 해놨지 구현은 하지 않았다. Delegate 패턴의 장점은 피위임자가 간호사일 때 출력결과와 의사일 때 출력결과를 보면 알 수 있듯이 피위임자만의 performCPR() 을 만들 수 있다.
이렇게 했을 때의 장점은 코드의 재사용하고 유지보수하기 쉬워진다.
performCPR() 과 같은 필요한 메서드를 정의만 해놓고, 필요한 곳에서 상황에 맞게 구현을 하고 사용을 하면 된다.

profile
매일 조금씩이라도 성장하자

0개의 댓글