[Design Pattern] Delegate

코르피·2022년 9월 13일
0

Delegate

Delegate란?

  • 위임자라는 말 그대로 프로그램에서 한 개체가 다른 개체를 대신하거나 연계하여 작동하는 패턴이다.

  • 이 디자인 패턴은 어떤 개체의 대신 해줄 기능들을 적어놓은 프로토콜을 정의해서 채택하는 위임자를 변수에 할당해서 사용하는 방식으로 사용한다.

  • 무조건 다른 개체를 만들어서 위임을 한 후 사용해야 하는 것은 아니다.
    자신에게 자신을 위임할 수도 있는데 예를 들어UITextFieldDelegate를 사용하는 경우, 자신(ViewController)에게 UITextFieldDelegate 를 채택시켜 메서드를 구현하면 자신에게 자신의 일을 위임한 형태가 되기 때문에 기능 확장으로 보일 수 있다.

Delegate를 쓰는 이유

공식문서 예제

공식문서의 Delegation 파트의 예제 코드 이다.

protocol DiceGame {
  var dice: Dice { get }
  func play()
}

protocol DiceGameDelegate: AnyObject {
  func gameDidStart(_ game: DiceGame)
  func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
  func gameDidEnd(_ game: DiceGame)
}

class SnakesAndLadders: DiceGame {
  let finalSquare = 25
  let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
  var square = 0
  var board: [Int]
  init() {
    board = Array(repeating: 0, count: finalSquare + 1)
    board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
    board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
  }
  weak var delegate: DiceGameDelegate?
  func play() {
    square = 0
    delegate?.gameDidStart(self)
    gameLoop: while square != finalSquare {
      let diceRoll = dice.roll()
      delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
      switch square + diceRoll {
      case finalSquare:
        break gameLoop
      case let newSquare where newSquare > finalSquare:
        continue gameLoop
      default:
        square += diceRoll
        square += board[square]
      }
    }
    delegate?.gameDidEnd(self)
  }
}

예제에서는 뱀사다리 게임클래스에서 게임시작, 게임진행, 게임종료 기능들을 위임자로 분리한 후 사용을 했다.
이 처럼 결국은 일의 기능을 분리해서 유지보수가 편하게 하고 책임을 낮게 가져가서 좀 더 가벼운 코드를 위해 사용하는 것이라고 생각한다.

만약 상속을 이용한다면 어떨까?

프로토콜을 이용하지않고 상속을 이용한 확장은 클래스가 불필요하게 비대해질 수 있다.
예를들어 게임심판 클래스를 두고 게임 승부 판단을 위해 심판을 상속한다면 승부판단을 위한 기능만이 아닌 심판의 다른 프로퍼티나 메서드 들도 따라 오게된다.
그래서 그 기능만을 가지고 있다고 보증하는 프로토콜을 사용해서 사용하는 것이 좋다.

동기, 비동기 문제

다른 예를 들어서 내가 피자를 시켜먹는 경우다. 만약 내가 피자를 시켜먹는데 직접가서 만들고 포장을 해온다면 어떨까? 나는 동기처리를 한 것이다.
내가 피자를 주문을 해서 그 시간에 다른 일을 할 수 있다면 훨씬 효율적이지 않을까?
delegate도 마찬가지이다. 자신의 일을 delegate에 위임함으로써 위임자가 대신 일을 처리하고 그 동안 다른 일을 처리할 수 있어서 훨씬 효율적이다.

사용 예제

// 피자 주문을 하는 기능을 가진 사람 클래스
class Person {
    weak var deliver: DeliveryDelegate?
    
    init(deliver: DeliveryDelegate) {
        self.deliver = deliver
    }
    
    func orderPizza() {
        deliver?.deliver()
    }
}

// 배달 프로토콜
protocol DeliveryDelegate: AnyObject {
    func deliver()
}

// 배달 프로토콜을 채택한 배달원 클래스
class PizzaDeliver: DeliveryDelegate {
    func deliver() {
        print("피자를 배달합니다")
    }
}

let pizzaDeliver = PizzaDeliver()
let hungryMan = Person(deliver: pizzaDeliver)
hungryMan.orderPizza() // print "피자를 배달합니다"

간단한 예제를 만들어보았다
피자배달원을 생성하고 배고픈 사람에게 배달원을 초기화 시킨 후
배고픈 사람이 주문을 한다.

배고픈 사람이 주문을 한 순간 배달을 위임한 배달원이 피자를 배달하고 "피자를 배달합니다"문구를 출력한다.

느낀점

근본적인 이해가 중요하다 근본적인 이해가....

profile
행복합시다!!

0개의 댓글