콘텐츠로 이동

2025 09 12

2025-09-12

Facade 패턴

참고: https://velog.io/@bagt/Design-Pattern-Facade-Pattern-%ED%8D%BC%EC%82%AC%EB%93%9C-%ED%8C%A8%ED%84%B4

  • 개요
    • 구조 패턴의 한 종류
    • 복잡한 서브 클래스들의 공통적인 기능을 정의하는 상위 수준의 인터페이스를 제공하는 패턴
  • 특징
    • 서브 클래스의 코드에 의존하는 일 감소
    • 복잡한 소프트웨어를 간단히 사용할 수 있게 간단한 인터페이스 제공
    • Sub-system 종속성 줄일 수 있으며, 파사드 객체 사용하는 곳에서는 여러 서브 클래스 호출할 필요없이 편리하게 사용가능
  • 장점
    • 낮은 결합도
    • 가독성 상승
    • 서브 시스템 직접 접근 가능

Actor & Future

  • Actor + Future 조합에서 sender()

    • Future 콜백은 다른 스레드에서 추후 처리됨
    • 이 시점에서 액터가 타 메시지를 처리하고 있다면, sender가 예상과 다를 수 있음
      private def processUpdate(testData: TestData) = {
          // 1. Future 시작 (비동기)
          testService.findUserById(testData.userId).map { user =>
              // 3. 나중에 실행됨 (다른 스레드에서!)
              // 이 시점에 sender()는 이미 다른 Actor를 가리킬 수 있음
              otherActor ! UpdateMessage(user, testData.approvalAt)
          }
          // 2. 즉시 리턴 (Future 완료를 기다리지 않음)
      }
      
    • 따라서 sender를 캡쳐하거나, pipe 패턴 사용을 권장
      case SomeMessage =>
          val originalSender = sender()  // 미리 저장
      
          someService.findSomething().map { result =>
              originalSender ! Response(result)  // 안전!
          }
      
      import akka.pattern.pipe
      
      case SomeMessage =>
          someService.findSomething()
              .pipeTo(sender())  // 자동으로 sender 캡처
      
  • 액터의 쓰레드 모델
    • 액터 인스턴스 관점에서, 각 액터는 한번에 하나의 메시지만 처리함.
      • 동시에 여러 메시지를 처리하지 않아 쓰레드 세이프
      • Actor가 하나의 쓰레드와 매칭되어 처리되는 방식
        • 고정된 쓰레드만 Actor에게 할당하는 방식은 아님
          Actor {
              Mailbox: [Msg1, Msg2, Msg3]
              Dispatcher가 스레드 할당
              한 번에 하나씩 처리 (순차적)
          }