디자인 패턴 - 싱글톤 / 델리게이트 / 옵저버

JG Ahn·2025년 1월 6일

iOS

목록 보기
15/32
post-thumbnail

디자인 패턴은 프로그램 개발에서 자주 나타나는 문제를 해결하기 위한 방법 중 하나로, 과거의 소프트웨어 개발 과정에서 발견된 설계 노하우를 축적하고 좋은 형태로 규약을 묶어 정리한 것이다.

이미 수많은 개발자들로부터 증명된 솔루션이기 때문에 패턴을 잘 사용한다면 보다 쉽게 설계할 수 있다.

다만 디자인 패턴을 맹신하고 패턴 적용에 얽매이지 않도록 하는 것이 중요하다. 패턴의 특징을 이해하고 상황에 맞게 사용할 수 있도록 해야겠다.

싱글톤 패턴

싱글톤 패턴은 특정 클래스의 인스턴스가 앱 전체에서 하나만 존재하고 앱 전역에서 모두 접근할 수 있게 한다. 이러한 특성 때문에 싱글톤은 인스턴스를 관리하기 쉽고 메모리를 절약하기 좋다는 장점이 있다.

싱글톤 패턴 사용의 예시 - 위치 서비스, 로깅 서비스, UserDefaults 전체 관리 클래스, 네트워크 중복 로직 관리 클래스 등

전반적인 관리 역할을 하는 클래스는 Manager라는 키워드를 붙여 네이밍한다. ex) NetworkManager

import Foundation

// 싱글톤 클래스.
class SingletonPractice {
	// shared를 통해 싱글톤 접근
    static let shared = SingletonPractice()
    var words = "singleton"
    var number = 20
    
    // 생성자를 private으로 선언해서 추가적으로 인스턴스를 생성하지 못하도록 함
    private init() {}
    
    func printInfo() {
        print("words: \(words)")
        print("number: \(number)")
    }
}

// shared를 통해 싱글톤 사용
SingletonPractice.shared.printInfo() //결과 : "words: singleton", "number: 20"
SingletonPractice.shared.words = "pattern"
SingletonPractice.shared.number = 30
SingletonPractice.shared.printInfo() //결과 : "words: pattern", "number: 30"

델리게이트 패턴

Delegate : 대리자, 위임자

객체 A의 일을 객체 B에게 대신 처리하게 하는 패턴. UIKit 내부에서도 많이 사용되는 패턴이다.

import Foundation

//바리스타 프로토콜
//이 프로토콜을 채택하면 커피를 만드는 책임을 갖게된다.
protocol Barista: AnyObject {
    func makeCoffee() -> String
}

class Starbucks {
    //delegate로 바리스타 프로토콜을 만족하는 클래스를 찾는다
    weak var delegate: Barista?
    
    init() {}
    
    //커피를 제공하는 메소드
    //커피는 delegate가 만들고 Starbucks는 그 결과를 사용
    func serveCoffee() {
        guard let coffee = delegate?.makeCoffee() else { return }
        print("주문하신 \(coffee) 나왔습니다.")
    }
}

//인스턴스 생성
let starbucks = Starbucks()

//바리스타 프로토콜을 만족하는 Jack 클래스
//Starbucks의 delegate(위임자)가 될 수 있음
class Jack: Barista {
    func makeCoffee() -> String {
        "아이스 아메리카노"
    }
}

let jack = Jack()

//jack에게 바리스타를 위임
starbucks.delegate = jack

//위임자를 사용해서 커피 제공
starbucks.serveCoffee()// 결과: "주문하신 아이스 아메리카노 나왔습니다."
  • 델리게이트 패턴의 특징
    • Starbucks 클래스는 누가 커피를 만들어주더라도 상관 없음. Barista 프로토콜을 채택한 클래스가 대신해주면 된다.
    • 프로토콜을 채택했기 때문에 수정이 용이하다.
class Chuck: Barista {
    func makeCoffee() -> String {
        "카페라떼"
    }
}

let chuck = Chuck()

starbucks.delegate = chuck
starbucks.serveCoffee()//결과: "주문하신 카페라떼 나왔습니다."

해당 코드를 위의 코드 아래에 적용하면 Starbucks 클래스가 새로운 커피를 만들기위해 내부 코드를 변경할 필요 없이 Chuck이라는 Barista 프로토콜을 채택한 클래스가 대신 새로운 커피 메뉴를 만들어준다.

이러한 이유로 클래스 타입보다 프로토콜 타입에 의존을 하는 경우가 좋은 구조이다. 이 철학은 객체지향 5대 원칙중 의존성 역전 원칙(DIP)와 연관이 있다.

UIKit의 Delegate 패턴 활용 예시

컬렉션뷰를 사용한 프로젝트의 컨트롤러의 코드 중 일부이다.

  • UIViewController 에서 UICollectionView.delegate = self 라는 코드를 작성해 컨트롤러가 위임자가 되겠다고 선언. self는 컨트롤러 본인을 가리킴

옵저버 패턴

객체의 상태가 변화할 때 그 객체를 관찰하는 구독자들에게 이벤트를 전달시켜주는 디자인 패턴.
이 때 이벤트를 발행하는 객체를 Publisher(Observable, Subject), 구독자를 Observer라고 한다.

iOS에서는 View가 Data를 구독해서 Data의 변화가 있을때 Data를 View에 적용하는 구조로 많이 사용된다. (= RxSwift, Rxcocoa)

0개의 댓글