대표 디자인 패턴의 힘
2019 년 5 월 29 일
지난 주 전에 우리는 며칠 만에 새로운 기능에 대해 너무 흥분했습니다. 그러나 다음 주 동안 워드프레스 관련 게시물을 유지합시다. 이번 주에 우리는 내가 가장 좋아하는 디자인 패턴 대리인에 대해 이야기 할 것입니다. 대리자는 가장 간단하고 강력한 패턴입니다.
소프트웨어 엔지니어링에서 위임 패턴은 객체 구성이 상속과 동일한 코드 재사용을 달성 할 수있는 객체 지향 디자인 패턴입니다. 위임에서 개체는 두 번째 개체(대리자)에 위임하여 요청을 처리합니다. 대리자는 도우미 개체이지만 원래 컨텍스트가 있습니다.
프로토콜
우리는 매일 위임 패턴을 사용합니다. 또한 셀 선택 및 다른 작업을 위임합니다. 대리자 패턴의 또 다른 훌륭한 예는 플로우 컨트롤러 또는 코디네이터입니다. 뷰 컨트롤러는 코디네이터에 탐색 논리를 위임합니다. 탐색 논리를 플로우 컨트롤러로 추출하는 것에 대한 게시물을 분리했습니다.
코드 샘플을 살펴 보겠습니다. 당신이 게임을하고 있다고 가정하십시오. 게임 로직을 분리 된 클래스 게임으로 추출했습니다.이 게임을 렌더링하는 게임 상태 변경 사항을 사용자 뷰 컨트롤러에 위임하려고합니다.
protocol GameDelegate: AnyObject { func stateChanged(from oldState: Game.State, to newState: Game.State)}class Game { private var state: State = .notStarted { didSet { delegate?.stateChanged(from: oldValue, to: state) } } weak var delegate: GameDelegate? private(set) var value: Int = 0 func start() { state = .started } func generateNextValue() { value = Int.random(in: 0..<1000) state = generateState(using: value) }}extension Game { enum State { case notStarted case started case right case win case lost }}
여기에 임의의 값을 생성하는 간단한 게임의 소스 코드입니다. 게임 엔진은 임의의 값을 기반으로 상태를 생성합니다. 모든 상태 변경 호출 대리인은 이전 상태와 새 상태를 전달합니다. 즉,유일한 클래스 인스턴스가 그것을 받아 들일 수 있음을 의미합니다. 또한 약한 키워드를 사용하여 변수 보유 대리자를 정의합니다. 그것은 대리자와 게임 클래스 사이의 유지주기를 깰 필요. 이제 게임 뷰 컨트롤러를 살펴 보자.
class GameViewController: UIViewController { private let game: Game init(game: Game) { self.game = game super.init(nibName: nil, bundle: nil) } @IBAction func play() { game.start() } @IBAction func next() { game.generateNextValue() } override func viewDidLoad() { super.viewDidLoad() game.delegate = self }}extension GameViewController: GameDelegate { func render(_ state: Game.State) { switch state { case .lost: renderLost() case .right: renderRight() case .win: renderWin() case .started: renderStart() case .notStarted: renderNotStarted() } } func stateChanged(from oldState: Game.State, to newState: Game.State) { render(newState) }}
여기에 사용자 작업 및 렌더링 상태 변경으로 게임을 공급하는 게임 뷰 컨트롤러 클래스가 있습니다. 게임 뷰 컨트롤러는 게임 레게이트를 준수하고 확장에 필요한 모든 렌더링을 구현합니다. 그 결과,우리는 대리자 디자인 패턴의 도움으로 구성 가능한 코드베이스를 가지고있다.
클로저
대리자에 메서드가 하나만 있는 경우 이 메서드를 클로저로 바꿀 수 있습니다. 이 아이디어는 동일하지만 이제는 클로저를 호출하고 프로토콜로 메소드를 호출하는 대신 상태를 전달합니다. 의 폐쇄와 예제를 살펴 보자.
class Game { typealias StateHandler = (State) -> Void var handler: StateHandler? private var state: State = .notStarted { didSet { handler?(state) } }}class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() game.handler = { state in self?.render(state) } }}
당신이 볼 수 있듯이,우리는 상태 변경을 처리하는 게임 클래스 인스턴스에 폐쇄를 전달합니다. 우리는 약한 것을 사용하여 클로저의 컨텍스트 캡처 중에 유지주기를 끊습니다. 여기서 또 다른 옵션은 모든 스위프트 기능이 클로저라는 사실의 사용 일 수 있습니다. 따라서 분리 된 클로저를 만드는 대신 함수 이름을 전달할 수 있습니다. 그러나,이 방법은 원을 유지 생성주의하십시오. 여기에 우리가 할 수있는 방법의 예입니다.
class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() game.handler = render }}extension GameViewController { func render(_ state: Game.State) { switch state { case .lost: renderLost() case .right: renderRight() case .win: renderWin() case .started: renderStart() case .notStarted: renderNotStarted() } }}
결론
오늘 우리는 이오스 개발에서 가장 강력하고 간단한 디자인 패턴을 논의했다. 나는 그것이 얼마나 간단하고 코드베이스를 분리하기 위해 조각을 구성하는 데 얼마나 유용 할 수 있는지 즐긴다. 트위터에 나를 따라이 게시물에 관련된 질문을 주시기 바랍니다. 읽어주셔서 감사드리며 다음주에 뵙겠습니다!