[λ””μžμΈ νŒ¨ν„΄] 싱글톀 νŒ¨ν„΄μ΄λž€? (iOS - Singleton Design Pattern) + μ˜μ‘΄μ„± μ£Όμž… (DI)

2022. 12. 24. 19:36ㆍComputerScience/DesignPattern

 

 

β ‡ 싱글톀 νŒ¨ν„΄ (Singleton Pattern)

  • ν•˜λ‚˜μ˜ ν΄λž˜μŠ€μ— ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ§Œ κ°€μ§€λŠ” νŒ¨ν„΄
  • λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° λͺ¨λ“ˆμ— 많이 μ‚¬μš©λ¨
  • iOS μ—μ„œλ„ 많이 μ μš©λ˜λŠ” μ€‘μš”ν•œ λ””μžμΈ νŒ¨ν„΄ 쀑 ν•˜λ‚˜
  • μ—¬λŸ¬ νŒŒμΌμ—μ„œ λ™μΌν•œ 객체λ₯Ό ν™œμš©ν•΄μ•Ό ν•˜λŠ” 경우, 싱글톀 νŒ¨ν„΄μ„ λ– μ˜¬λ¦¬μž

 

  • 싱글톀 νŒ¨ν„΄ -> 객체가 μƒμ„±λ˜λ©΄ μž„μ˜λ‘œ λ©”λͺ¨λ¦¬μ—μ„œ ν•΄μ œν•˜μ§€ μ•ŠλŠ” 이상 ν”„λ‘œκ·Έλž¨μ΄ 끝날 λ•ŒκΉŒμ§€ λ©”λͺ¨λ¦¬μ— μœ μ§€λ¨
  • ν”„λ‘œμ νŠΈ λ‚΄μ—μ„œ 객체λ₯Ό ν•˜λ‚˜λ§Œ μƒμ„±ν•˜μ—¬ 곡용으둜 μ‚¬μš©ν•˜λŠ” 경우 ν™œμš©
// Shared URL Session
let sharedURLSession = URLSession.shared

// Default File Manager
let defaultFileManager = FileManager.default

// Standard User Defaults
let standardUserDefaults = UserDefaults.standard

// Default Payment Queue
let defaultPaymentQueue = SKPaymentQueue.default()
let screen = UIScreen.main
let useDefault = UserDefaults.standard
let application = UIApplication.shared
let fileManager = FileManager.default
let notification = NotificationCenter.default

 

 

 

 

# ν”„λ‘œμ νŠΈμ—μ„œ ν™œμš©ν•œ μ˜ˆμ‹œ μ½”λ“œλ“€ 

# TARS - SPACEOVER: https://github.com/DeveloperAcademy-POSTECH/MacC-Team-TARS

 

GitHub - DeveloperAcademy-POSTECH/MacC-Team-TARS: μ‹œκ°μž₯애인이 우주λ₯Ό κ²½ν—˜ν•  수 μžˆλŠ” μ•±

μ‹œκ°μž₯애인이 우주λ₯Ό κ²½ν—˜ν•  수 μžˆλŠ” μ•±. Contribute to DeveloperAcademy-POSTECH/MacC-Team-TARS development by creating an account on GitHub.

github.com

class LocationManager: NSObject, CLLocationManagerDelegate {
    static let shared = LocationManager()
    weak var delegate: LocationManagerDelegate?

    private let locationManager = CLLocationManager()
    private var location: CLLocation?
    private var isLocationUpdated: Bool = false

    override init() {
        super.init()
        locationManager.delegate = self
    }
class AudioManager {
    static let shared = AudioManager()
    var audioPlayer: AVAudioPlayer?
    
    init() {}

Hint - static let shared

 

 

 

 

싱글톀 νŒ¨ν„΄μ˜ μž₯단점

  • ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ—¬ 곡유 -> 생성 λΉ„μš©μ΄ 쀄어든닀
  • But μ˜μ‘΄μ„±μ΄ λ†’μ•„μ§„λ‹€λŠ” 단점
    • TDD (Test Driven Development) ν…ŒμŠ€νŠΈ 주도 개발 μ‹œ 문제
      • λ‹¨μœ„ ν…ŒμŠ€νŠΈ - ν…ŒμŠ€νŠΈκ°€ μ„œλ‘œ 독립적이어야 ν•œλ‹€.
      • ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 기반으둜 κ΅¬ν˜„ -> ν…ŒμŠ€νŠΈλ§ˆλ‹€ 독립적인 μΈμŠ€ν„΄μŠ€ 생성이 μ–΄λ ΅λ‹€
    • μ˜μ‘΄μ„± μ£Όμž… (DI, Dependency Injection)
      • 싱글톀 νŒ¨ν„΄μ€ 쉽고 μ‹€μš©μ μ΄λ‚˜, λͺ¨λ“ˆ κ°„μ˜ 결합을 κ°•ν•˜κ²Œ ν•œλ‹€. 
      • μ˜μ‘΄μ„± μ£Όμž…μ„ 톡해 λͺ¨λ“ˆ κ°„μ˜ 결합을 λŠμŠ¨ν•˜κ²Œ λ§Œλ“€μ–΄ ν•΄κ²°ν•  수 μžˆλ‹€.
      • 메인 λͺ¨λ“ˆ -> μ˜μ‘΄μ„± μ£Όμž…μžκ°€ κ°€λ‘œμ±” -> 메인 λͺ¨λ“ˆμ€ ν•˜μœ„ λͺ¨λ“ˆμ— λŒ€ν•œ μ˜μ‘΄μ„±μ΄ λ–¨μ–΄μ§€κ²Œ λœλ‹€ (λ””μ»€ν”Œλ§ λœλ‹€)
      • μ˜μ‘΄μ„± μ£Όμž… 원칙: μƒμœ„ λͺ¨λ“ˆμ€ ν•˜μœ„ λͺ¨λ“ˆμ—μ„œ μ–΄λ– ν•œ 것도 κ°€μ Έμ˜€μ§€ μ•Šμ•„μ•Ό ν•œλ‹€ / λ‘˜ λ‹€ 좔상화 원칙에 μ˜μ‘΄ν•΄μ•Ό ν•˜λ©°, μ΄λ•Œ μΆ”μƒν™”λŠ” μ„ΈλΆ€ 사항에 μ˜μ‘΄ν•˜μ§€ 말아야 ν•œλ‹€.

 

 

 

μ˜μ‘΄μ„± μ£Όμž…μ— λŒ€ν•΄ 더 μ•Œμ•„λ³΄κΈ°

  • Dependency Injection means giving an objects its instance variable. Really. That's it - James Shore
  • μ˜μ‘΄μ„± μ£Όμž…μ΄λž€, 객체 κ°„ 결합을 λŠμŠ¨ν•˜κ²Œ ν•˜κΈ° μœ„ν•˜μ—¬, νŠΉμ • 객체의 속성을 μžμ‹ μ΄ μ•„λ‹Œ λ‹€λ₯Έ 객체가 μ΄ˆκΈ°ν™”ν•˜λŠ” 것
  • λŠμŠ¨ν•œ κ²°ν•© -> μ£Όμž…λ°›λŠ” μ†μ„±μ˜ νƒ€μž…μ„ ν”„λ‘œν† μ½œλ‘œ 생성 -> ν…ŒμŠ€νŠΈκ°€ μš©μ΄ν•΄μ§€κ³ , μ˜λ„κ°€ λͺ…ν™•ν•œ μ½”λ“œ

 

  • 의쑴 κ΄€κ³„λŠ” ν•œ ν΄λž˜μŠ€κ°€ λ‹€λ₯Έ ν΄λž˜μŠ€μ—μ„œ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯을 μ‚¬μš©ν•  λ•Œ λ°œμƒ !
  • ν”„λ‘œν† μ½œ ν™œμš© - λͺ¨λ“  κΈ°λŠ₯이 μ•„λ‹ˆλΌ, ν•„μš”ν•œ μ œν•œλœ κΈ°λŠ₯λ§Œμ„ μ œκ³΅λ°›μ„ 수 μžˆμ–΄ λΆˆν•„μš”ν•œ μ½”λ“œ ν™•μž₯이 없어짐
  • μ˜μ‘΄μ„± μ£Όμž…μ˜ μž₯점: μ±…μž„μ΄ μ’€ 더 λͺ…확해진 클래슀λ₯Ό 얻을 수 μžˆλ‹€. μ–΄λ–€ 의쑴 관계와 μš”κ΅¬μ‚¬ν•­μ΄ μžˆλŠ”μ§€ μˆ˜μ›”ν•˜κ²Œ 확인 κ°€λŠ₯
    Testable ν•œ 클래슀λ₯Ό μ–»κ²Œ λœλ‹€. Protocol type으둜 받을 μ‹œ μ‰½κ²Œ Mock 였브젝트둜 λŒ€μ²΄ν•  수 있기 λ•Œλ¬Έ
    κ΄€μ‹¬μ‚¬μ˜ 뢄리 원칙을 잘 지킬 수 μžˆλ‹€ -> λ” 이상 의쑴 κ΄€κ³„μ˜ 객체의 μ΄ˆκΈ°ν™”μ— 직접 κ΄€μ—¬ν•  ν•„μš”κ°€ μ—†μŒ
    ν”„λ‘œν† μ½œμ„ μ‚¬μš©ν•œ μ˜μ‘΄μ„± μ£Όμž… -> κ²°ν•©λ„λ₯Ό 쀄이고, μ£Όμž…λœ 객체의 μ±…μž„μ„ λͺ…ν™•νžˆ ν•  수 μžˆλ‹€
  • Do not depend on Concretion, Depend on Abstraction

 

 

 

# 싱글톀 νŒ¨ν„΄

import StreamChat
import UIKit

/// 1: Extend the `ChatClient` class.
extension ChatClient {

    /// 2: Add a `shared` static variable of its own type.
    static var shared: ChatClient!
}

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        /// 3: Create a `Token` and `TokenProvider`.
        let token = Token("[jwt token]")
        let tokenProvider = TokenProvider.static(token)

        /// 4: Create a `ChatClientConfig` with the API key.
        let config = ChatClientConfig(apiKeyString: "[api_key]")

        /// 5: Set the shared `ChatClient` instance with the config and the token provider.
        ChatClient.shared = ChatClient(config: config, tokenProvider: tokenProvider)

        return true
    }
}

 

 

 

# μœ„μ˜ μ½”λ“œμ— μ˜μ‘΄μ„± μ£Όμž… DI 적용

import StreamChat
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    ) {
        guard let scene = (scene as? UIWindowScene) else { return }

        /// 1: Get the reference to the initial view controller
        let viewController = window?.rootViewController as? ViewController

        /// 2: Create a `ChatClientConfig` with the API key.
        let config = ChatClientConfig(apiKeyString: "[api_key]")

        /// 3: Create a `ChatClient` instance with the config and the tokenProvider.
        let chatClient = ChatClient(config: config, tokenProvider: tokenProvider)

        /// 4: Inject the `ChatClient` object into your `ViewController`.
        viewController?.chatClient = chatClient
    }
}

 

 

 

 

싱글톀 νŒ¨ν„΄μ˜ μ‚¬μš© μ˜ˆμ‹œ

  • Node.js μ—μ„œ MongoDB μ—°κ²°μ‹œ ν™œμš©ν•˜λŠ” mongoose λͺ¨λ“ˆ
  • Node.js μ—μ„œ MySQL μ—°κ²°μ‹œμ—λ„ 싱글톀 νŒ¨ν„΄μ΄ μ‚¬μš©λ¨
  • iOS μ½”λ“œ ꡬ석ꡬ석 정말 많이 μ‚¬μš©λ¨ (μœ„μ˜ μ˜ˆμ‹œλ“€)

 

 

 

좜처

 

 

Singleton vs Dependency Injection in Swift

When coding iOS apps, we often create classes that manage a particular aspect of the application. For example, it's common to develop "manager" classes that encapsulate methods for interacting with a specific application aspect. These aspects commonly incl

getstream.io