티스토리 뷰

카테고리 없음

Delegate 패턴

ccc124213131 2022. 12. 11. 11:24
728x90

delegate 패턴은 특정 이벤트가 발생할 때 한 개체가 다른 개체로 정보를 보낼 수 있도록 하는 디자인 패턴입니다. 특정 이벤트가 발생할 때 한 개체(Observer)가 다른 개체(Subject)로부터 알림을 수신하기 위해 등록하는 옵저버 패턴을 구현하는 데 종종 사용됩니다.

 

delegate 패턴의 작동 방식을 설명하는 데 도움이 되는 비유는 다음과 같습니다.

파티를 조직하고 있으며 일부 작업을 다른 사용자에게 위임한다고 가정합니다. 여러분은 파티에서 친구에게 DJ와 음악 연주를 부탁할 수도 있고, 다른 친구에게 파티에서 사진작가와 사진을 찍어달라고 부탁할 수도 있습니다. 이 경우 사용자는 "주체"이고 친구는 "위임자"입니다.

파티에서 음악이 재생되기를 원하고 사진이 찍히기를 원하지만 이러한 작업이 어떻게 수행될지에 대한 구체적인 세부 사항은 알지 못합니다. 대신, 여러분은 친구들이 이러한 일을 처리할 것이라고 믿고 그들에게 책임을 위임합니다. 파티가 열릴 때는 친구(위임자)에게 음악과 사진 작업을 맡겨야 합니다.

 

이 비유에서 "위임 프로토콜"은 다른 사용자에게 위임하려는 태스크의 목록입니다. 위임 속성은 작업을 처리할 특정 사용자입니다. 그리고 "알림"은 여러분이 친구들에게 그 일을 처리하도록 요청하는 것입니다.

파티에서 다른 사람에게 작업을 위임할 수 있는 것처럼 Swift의 개체는 위임 패턴을 사용하여 다른 개체에 책임을 위임할 수 있습니다. 위임 패턴을 사용하면 제목이 위임자에게 무언가를 알리거나 위임자가 무언가를 수행하도록 요청할 때 적절한 위임자에게 메시지를 보낼 수 있습니다.

protocol PartyDelegate: class {
    func playMusic()
    func takePictures()
}

class PartyOrganizer {
    weak var delegate: PartyDelegate?

    func startParty() {
        // set up the party...
        
        // request that the delegate play music
        delegate?.playMusic()
        
        // request that the delegate take pictures
        delegate?.takePictures()
    }
}

class DJ: PartyDelegate {
    func playMusic() {
        // play some music at the party
    }
    
    func takePictures() {
        // do nothing, because the DJ is not responsible for taking pictures
    }
}

class Photographer: PartyDelegate {
    func playMusic() {
        // do nothing, because the photographer is not responsible for playing music
    }
    
    func takePictures() {
        // take some pictures at the party
    }
}

let partyOrganizer = PartyOrganizer()
let dj = DJ()
let photographer = Photographer()

partyOrganizer.delegate = dj
partyOrganizer.startParty()

이 예에서는 다음을 수행합니다.

파티 대표자 프로토콜이 정의되어 있으며, 이 프로토콜은 대표자가 구현할 수 있는 playMusic 및 takePictures 메서드를 지정합니다.

파티 주최자 클래스에 파티 대표 유형의 위임 속성이 있습니다. 이 속성은 유지 주기를 피하기에 약합니다.

DJ 클래스와 포토그래퍼 클래스는 모두 파티 대표 프로토콜을 준수하며, 이는 그들이 플레이 뮤직과 사진 촬영 방법을 모두 구현한다는 것을 의미합니다.

partyOrganizer에서 startParty 메서드를 호출할 때, 이 메서드는 위임 개체(dj)에서 playMusic 메서드를 호출하여 음악을 재생하도록 요청하고, 또한 위임 개체에서 takePictures 메서드를 호출하여 사진을 찍도록 요청합니다.

이 예에서 위임 패턴은 다음과 같이 작동합니다. PartyOrganizer 클래스는 위임자(DJ 및 Photographer)가 구현할 수 있는 프로토콜을 정의하고 PartyOrganizer 클래스는 위임 개체에 대한 속성을 가집니다. 파티 주최자는 대리인 개체에 대한 적절한 메서드를 호출하여 대리인에게 요청을 보냅니다.

아래는 예시 코드 입니다.

protocol MyDelegate: class {
    func didUpdateValue(value: Int)
}

class MySubject {
    weak var delegate: MyDelegate?

    func updateValue() {
        let newValue = 5

        // 값이 업데이트되면 delegate에게 알려줍니다.
        delegate?.didUpdateValue(value: newValue)
    }
}

class MyObserver: MyDelegate {
    func didUpdateValue(value: Int) {
        // 업데이트된 값을 여기서 다루면 됩니다.
    }
}

let subject = MySubject()
let observer = MyObserver()

subject.delegate = observer
subject.updateValue()

위 코드에서 MyObserver는 MyDelegate 프로토콜을 준수합니다. 즉, didUpdateValue 메서드를 구현합니다. MySubject에는 옵저버 개체가 할당된 MyDelegate 타입의 delegate 프로퍼티가 있습니다. subject가 updateValue를 호출하면 내부 값을 업데이트한 다음 delegate에서 didUpdateValue 메서드를 호출하여 값이 업데이트되었음을 delegate에게 알립니다.

다음은 실제 시나리오에서 delegate 패턴을 사용하여 뷰 컨트롤러 간에 메시지를 전달하는 방법에 대한 예입니다.

사용자 이름과 암호 텍스트 필드가 있는 로그인 화면과 로그인 버튼이 있다고 가정해 보겠습니다. 사용자가 로그인 버튼을 누르면 사용자 이름과 암호를 확인한 다음 로그인이 성공하면 다른 보기 컨트롤러를 표시합니다. 다음을 수행하여 위임 패턴을 사용하여 이를 수행할 수 있습니다.

  1. 메서드 didLogin(사용자 이름: String) 로그인이 성공하면 호출됩니다.
  2. LoginDelegate 프로토콜을 준수하는 LoginViewController 클래스를 만듭니다. 이 클래스는 사용자 이름 및 암호 텍스트 필드와 로그인 단추를 처리합니다.
  3. LoginViewController에서 LoginDelegate 유형의 위임 속성을 생성하여 성공적인 로그인을 처리할 개체에 할당합니다.
  4. 사용자가 로그인 버튼을 누르면 LoginViewController가 사용자 이름과 암호를 확인하고 올바른 경우 대리자의 didLogin 메서드를 호출합니다.
  5. LoginDelegate 프로토콜(예: 다른 뷰 컨트롤러)을 준수하는 개체에서 didLogin 메서드를 구현하여 성공적인 로그인을 처리합니다. 여기에는 예를 들어 다른 뷰 컨트롤러를 표시하는 것이 포함될 수 있습니다.

코드는 다음과 같습니다.

protocol LoginDelegate: class {
    func didLogin(username: String)
}

class LoginViewController: UIViewController, LoginDelegate {
    var delegate: LoginDelegate?

    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!

    @IBAction func loginButtonTapped() {
        // validate the username and password
        let username = usernameTextField.text
        let password = passwordTextField.text

        if validateCredentials(username: username, password: password) {
            // login was successful, so call the didLogin method on the delegate
            delegate?.didLogin(username: username)
        }
    }
}

class HomeViewController: UIViewController, LoginDelegate {
    func didLogin(username: String) {
        // show the home screen for the user with the given username
    }
}

let loginViewController = LoginViewController()
let homeViewController = HomeViewController()

// set the loginViewController's delegate to the homeViewController
loginViewController.delegate = homeViewController

이 예에서 HomeViewController 클래스는 LoginDelegate 프로토콜을 준수하므로 LoginViewController의 위임자로 할당할 수 있습니다. 사용자가 성공적으로 로그인하면 LoginViewController가 대리자의 didLogin 메서드를 호출합니다. 이 경우에는 HomeViewController입니다. 그러면 HomeViewController가 적절한 보기를 표시하여 성공적인 로그인을 처리할 수 있습니다.

댓글