[Swift] 싱글톤(Singleton) 패턴
싱글톤 패턴이란?
싱글톤(Singleton) 패턴은 GoF 디자인 패턴 중 생성 패턴에 속하는 디자인 패턴으로, 객체의 인스턴스가 한 번만 생성되는 패턴이다.
생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초에 생성한 객체를 리턴한다.
이는 앱의 라이프사이클 동안 오직 하나의 클래스 인스턴스만 메모리에 올려두고 재사용하는 것을 의미한다.
Swift로 한 번 구현을 해보자.
`User`라는 클래스가 있을 때, `static`으로 인스턴스를 저장할 프로퍼티를 생성해준다.
그리고 사용자가 `init` 함수를 호출해서 인스턴스를 생성하는 것을 막기 위해 `init` 함수 접근제어자를 `private`으로 설정해준다.
class User {
static let shared = User()
let name = "siro"
private init() { }
}
이제 `User` 클래스 안의 정보를 얻고싶다면 `shared`를 이용해주면 된다.
let user = User.shared
print(user.name)
다른 예시를 한 번 구현해보겠다!
어떤 마켓이 하나 있는데 마켓의 물건을 온라인에서도 구매할 수 있고, 오프라인으로도 구매할 수 있다고 해보자.
구매할 수 있는 곳은 두 곳이지만 실제로 존재하는 마켓은 하나이므로 그 마켓의 재고는 온라인이든 오프라인이든 동일해야 한다.
싱글톤으로 구현을 하면 다음과 같다.
재고를 관리하기 위해 `enum`으로 물건의 종류를 정의해주고, 해당 물건 별 재고는 100으로 초기화해두었다.
`sell()` 함수로 물건을 팔 수 있고, 물건은 하나씩만 팔린다. `checkCount()` 함수로 남은 재고를 확인한다.
enum ProductType {
case snack
case drinks
case chocolate
}
class Market {
static let shared = Market()
private var snackCount = 100
private var drinksCount = 100
private var chocolateCount = 100
private init() { }
func sell(_ type: ProductType) {
switch(type) {
case .snack:
snackCount -= 1
case .drinks:
drinksCount -= 1
case .chocolate:
chocolateCount -= 1
}
}
func checkCount() {
print("남은 재고: 과자(\(snackCount)), 음료수(\(drinksCount)), 초콜릿(\(chocolateCount))")
}
}
온라인 판매용 인스턴스와 오프라인 판매용 인스턴스를 각각 생성한 후
온라인으로 초콜릿 하나, 오프라인으로 과자 하나를 판매했다.
let online = Market.shared
let offline = Market.shared
online.sell(.chocolate)
offline.sell(.snack)
Market.shared.checkCount()
checkCount() 함수로 재고를 확인해보면 하나의 공간에서 재고가 관리되는 것을 확인할 수 있다.
Swift의 싱글톤 활용
Swift에서 활용하는 싱글톤에는 아래와 같은 것들이 있다.
- UserDefaults.standard
- NotificationCenter.default
- URLSession.shared
- UIScreen.main
- UIApplication.shared
- FileManager.default
익숙하지만 싱글톤이라고는 인지하지 못했던 것들인 것 같다.
싱글톤 패턴의 장점과 단점
먼저 장점은
1. 하나의 인스턴스로 공유하므로 메모리 낭비를 방지할 수 있다.
2. 다른 클래스와 자원 공유가 쉽다.
단점은
1. 싱글톤 인스턴스가 너무 많은 일을 하게 되면, 해당 자원을 공유하는 여러 클래스 간 결합도가 높아져 OCP(개방-폐쇄 원칙)을 위배하게 된다.
OCP(Open-Closed Principle)는 모듈의 확장에는 열려있어야 하고, 변경에는 닫혀있어야 한다는 객체지향설계 원칙 중 하나이다.
2. 이에 따라 수정이 어려워진다.
싱글톤은 클래스로 구현해야 하는가..?
싱글톤 패턴은 Swift에서 주로 클래스로 구현을 한다. 그렇다면 구조체로 구현할 수는 없을까??
https://devs1ro-o.tistory.com/5
[Swift] struct와 class
본 글은 Swift Language Guide 한국어 번역본을 참고하여 작성하였습니다.기본적인 struct와 class구조체와 클래스는 모두 데이터를 캡슐화하는 사용자 정의 타입을 모델링한다.정의 구문구조체와 클래
devs1ro-o.tistory.com
위 글에서 설명하였듯이 클래스는 참조 타입이고, 구조체는 값 타입이다.
참조 타입인 인스턴스를 복사한다면 같은 메모리 주소를 참조하는 인스턴스의 원본을 공유하게 되지만, 값 타입을 복사한다면 새로운 복사본이 생성되는 것이다.
그렇게 된다면 ‘유일한 객체’가 아니게 되므로 싱글톤 패턴이 깨지는 것이다.
그치만? 정의한 구조체를 인스턴스화 하지 않는다면 싱글톤처럼 쓸 수는 있다.
결론은 구조체로도 싱글톤을 구현할 수 있지만, 인스턴스화 하지 않을 때만 가능하다는 것~
그렇다면 인스턴스화 하지 않는 싱글톤 객체의 경우에 구조체로 구현하는 것이 더 좋은가? 이건 잘 모르겠다...
참고 자료
- https://babbab2.tistory.com/66
- https://yagom.net/courses/design-pattern-in-swift/