apple/DesignPattern, Architecture

Swift 디자인패턴 Multicast Delegate Pattern (멀티캐스트 딜리게이트 패턴)

lgvv 2022. 6. 7. 10:45

Swift 디자인패턴 Multicast Delegate Pattern (멀티캐스트 딜리게이트 패턴)

 

멀티캐스트 델리게이트 패턴델리게이트 패턴을 확장하여, 하나의 객체가 여러 개의 델리게이트에게 알림을 전송.

 

히스토리

  • 2022-06-07: 디자인 패턴 스터디 정리
  • 2024-11-26: 포스팅 글 재정리 및 예제 변경

multicast delegate pattern

 

Multicast Delegate Pattern

멀티캐스트 객체가 델리게이트 객체와의 관계가 일대일이 아닌 일대다로 확장되며, 여러 개의 델리게이트 객체가 이벤트를 수신하고 반응할 수 있음

  • 이 패턴의 핵심은 멀티캐스트 델리게이트 헬퍼 클래스로, 이 클래스는 여러 델리게이트를 관리하고, 델리게이트 객체들이 이벤트를 받을 수 있도록 함.
  • 헬퍼 클래스를 통해 한 객체가 여러 델리게이트에게 동일한 이벤트를 전달할 수 있도록 함
  • RxSwift나 Combine 등을 통해 손쉽게 처리 가능

멀티캐스트 딜리게이트 패턴은 일반적으로 3가지 개념으로 구성됨

  • 델리게이팅 객체 (Delegating Object): 이벤트가 발생했을 때 다른 객체들에게 알림을 보내는 객체
    • 여러 개의 델리게이트를 가질 수 있습니다.
  • 델리게이트 (Delegate): 델리게이트 프로토콜을 구현하고 이벤트에 반응하는 객체
  • 멀티캐스트 델리게이트 헬퍼 (Multicast Delegate Helper): 여러 델리게이트 객체를 관리하는 헬퍼 클래스
    • Delegating Object가 여러 Delegate에게 이벤트를 전달할 수 있도록 구조를 가짐
  • 델리게이트 프로토콜 (Delegate Protocol): 델리게이트가 구현해야 할 메서드를 정의하는 인터페이스

동작하는 방식 (코드 흐름)

  • Delegating Object 객체는 하나 이상의 Delegate를 가질 수 있으며, Delegate 들에게 이벤트가 발생했을 때 알림을 전달
  • Multicast Delegate Helper는 Delegating Object가 여러 Delegate를 등록하고, 각각의 Delegate가 이벤트를 수신하도록 관리
  • 여러 개의 Delgeate가 동일한 이벤트를 수신 할 수 있어, 여러 리스너들에게 동일한 알림을 효율적으로 전달

사용 예시

  • 여러개의 컴포넌트가 하나의 이벤트에 대해 수신해야 하는 경우에 사용하면 좋음

 

코드 예제

멀티 캐스트 패턴을 가장 일반적으로 사용한 예제

import UIKit
import SwiftUI

/// Protocol that defines delegate behavior
protocol EventDelegate: AnyObject {
    func didReceiveEvent(_ message: String)
}

/// A class for managing multiple delegates
class MulticastDelegate<T> {
    private var delegates = NSHashTable<AnyObject>.weakObjects() // Weak references to avoid retain cycles

    /// Add a delegate
    func addDelegate(_ delegate: T) {
        delegates.add(delegate as AnyObject)
    }

    /// Remove a delegate
    func removeDelegate(_ delegate: T) {
        delegates.remove(delegate as AnyObject)
    }

    /// Notify all delegates
    func invokeDelegates(_ closure: (T) -> Void) {
        for delegate in delegates.allObjects {
            if let delegate = delegate as? T {
                closure(delegate)
            }
        }
    }
}

/// An example broadcaster that uses the multicast delegate
class EventBroadcaster {
    private let multicastDelegate = MulticastDelegate<EventDelegate>()

    func addDelegate(_ delegate: EventDelegate) {
        multicastDelegate.addDelegate(delegate)
    }

    func removeDelegate(_ delegate: EventDelegate) {
        multicastDelegate.removeDelegate(delegate)
    }

    func broadcastEvent(message: String) {
        print("Broadcasting event: \(message)")
        multicastDelegate.invokeDelegates { delegate in
            delegate.didReceiveEvent(message)
        }
    }
}

/// Example delegate classes
class FirstListener: EventDelegate {
    func didReceiveEvent(_ message: String) {
        print("FirstListener received: \(message)")
    }
}

class SecondListener: EventDelegate {
    func didReceiveEvent(_ message: String) {
        print("SecondListener received: \(message)")
    }
}

struct ContentView: View {
    var body: some View {
        Button("Execute") {
            /// Example usage
            let broadcaster = EventBroadcaster()
            let firstListener = FirstListener()
            let secondListener = SecondListener()

            broadcaster.addDelegate(firstListener)
            broadcaster.addDelegate(secondListener)

            // Broadcast an event
            broadcaster.broadcastEvent(message: "Hello, Multicast Delegates!")

            // Remove a delegate and broadcast again
            broadcaster.removeDelegate(firstListener)
            broadcaster.broadcastEvent(message: "Only SecondListener should receive this.")
        }
    }
}

#Preview {
    ContentView()
}

 

결과!

 

 

(참고)

https://www.kodeco.com/books/design-patterns-by-tutorials/v3.0/chapters/16-multicast-delegate-pattern

 

Design Patterns by Tutorials, Chapter 16: Multicast Delegate Pattern

The multicast delegate pattern is a behavioral pattern that’s a variation on the delegate pattern. It allows you to create one-to-many delegate relationships, instead of one-to-one relationships in a simple delegate.

www.kodeco.com