디자인 패턴: 외관 패턴 🎭

표지 사진 by Silvio Kundt on Unsplash

파사드 패턴은 복잡한 외부 라이브러리나 서비스와 상호작용이 있을 때 일반적으로 사용되는 구조적 디자인 패턴입니다.

이 패턴에서는 타사 라이브러리와의 상호 작용을 캡슐화하는 클래스를 만듭니다. 이 클래스를 Facade라고 합니다. 이를 통해 애플리케이션의 나머지 부분에 더 간단한 인터페이스를 노출할 수 있습니다. 시스템의 다른 부분에서 작업하는 개발자는 타사 라이브러리를 배울 필요가 없습니다. 오히려 우리가 만든 파사드 클래스와만 인터페이스하면 됩니다.

이것은 몇 가지 중요한 목적을 수행합니다.
  • 타사 시스템이 매우 복잡하고 단일 작업을 수행하기 위해 여러 단계가 필요한 경우 파사드의 단일 기능으로 모든 것을 캡슐화할 수 있습니다.
  • 하나의 타사 라이브러리를 다른 라이브러리로 쉽게 전환할 수 있으며 여전히 외관에 대해 동일한 인터페이스를 유지할 수 있습니다. 이러한 유연성은 외관의 주요 판매 포인트 중 하나입니다.
  • 또한 애플리케이션에서 실제로 필요하지 않은 추가 기능을 외부 서비스에서 필터링할 수도 있습니다. 이것은 외부 라이브러리가 매우 포괄적일 수 있고 제공되는 모든 기능이 필요하지 않을 수 있기 때문에 파사드 패턴을 사용하는 동안 매우 일반적입니다.

  • 파사드 패턴을 사용하는 예를 들어보자

    아마존 주문 시스템



    Amazon에서 주문을 처리하는 모듈을 구축하고 있다고 가정해 보겠습니다. 이것을 구축하는 동안 주문을 하는 데 몇 가지 단계가 있음을 깨달았습니다. 여러 다른 시스템/모듈과의 상호 작용을 포함하는 각 단계.

    Note: This probably is not how Amazon has implemented it's order system. This is just a simplistic representation of what it could be



    단계를 나열해 보겠습니다.
  • 사용자 인증 - 사용자 서비스
  • 제품의 가용성 확인 - 제품 서비스
  • 사용자에게 제품 할당 - 제품 서비스
  • 결제하기 - 결제 서비스
  • 대리점에 알림 보내기 - 알림 서비스

  • 버튼 클릭으로 모든 것이 가능합니다 😱

    일반적으로 버튼 클릭으로 모든 시스템과 서비스를 직접 통합하면 코드의 가독성이 저하되고 한 서비스를 다른 서비스로 전환하는 것도 악몽이 될 것입니다(제품 서비스를 개편하는 경우를 상상해 보세요)

    이 모든 문제를 해결하기 위해 이 모든 것을 처리하고 위의 모든 단계를 완료하기 위해 placeOrderproductId를 사용하는 userId라는 함수를 노출하는 파사드 클래스를 만들 수 있습니다 👆🏽

    이동 중에 이 솔루션을 구현해 보겠습니다.

    type orderFacade struct {
        userService UserService
        productService ProductService
        paymentService PaymentService
        notificationService NotificationService
    }
    
    func (o *orderFacade) placeOrder(userId string, productId string) {
        fmt.Println("[Facade] Starting order placement")
    
        userValid := o.userService.isUserValid(userId)
        productAvailable := o.productService.productAvailable(productId)
    
        if userValid && productAvailable {
            o.productService.assignProductToUser(productId, userId)
            o.paymentService.makePayment(userId, productId)
            o.notificationService.notifyDealer(productId)
        }
    }
    


    다른 서비스의 코드도 살펴보겠습니다.

    type UserService struct {}
    
    func (u *UserService) isUserValid(userId string) bool {
        fmt.Println("[UserService] validating the user: ", userId);
        // Complex logic for checking validity
        return true
    }
    
    type ProductService struct {}
    
    func (p *ProductService) productAvailable(productId string) bool {
        fmt.Println("[ProductService] checking availability of product: ", productId)
        // Complex logic for checking availability
        return true;
    }
    
    func (p *ProductService) assignProductToUser(productId string, userId string) {
        fmt.Printf("[ProductService] assigning product %s to user %s\n", productId, userId)
        // complex logic for product assignment
    }
    
    type PaymentService struct {}
    
    func (p *PaymentService) makePayment(userId string, productId string) {
        fmt.Printf("[PaymentService] charging user %s for product %s\n", userId, productId)
        // complex logic for making payment
    }
    
    type NotificationService struct {}
    
    func (n *NotificationService) notifyDealer(productId string) {
        fmt.Printf("[NotificationService] notifying dealer about sale of product %s\n", productId)
        // complex notification logic
    }
    


    오오, 이제 우리는 더미 서비스와 완전히 합법적인 외관을 갖추었습니다 💁🏻‍♂️ - 테스트할 시간입니다

    func main() {
        orderModule := &orderFacade{
            userService:  UserService{},
            productService:  ProductService{},
            paymentService:  PaymentService{},
            notificationService:  NotificationService{},
        }
    
        userId := "test-user-id"
        productId := "test-product-id"
    
    
        orderModule.placeOrder(userId, productId)
    }
    


    프로그램을 실행하면 출력에 다음과 같은 내용이 표시되어야 합니다.

    [Facade] Starting order placement
    [UserService] validating the user:  test-user-id
    [ProductService] checking availability of product:  test-product-id
    [ProductService] assigning product test-product-id to user test-user-id
    [PaymentService] charging user test-user-id for product test-product-id
    [NotificationService] notifying dealer about sale of product test-product-id
    


    코드와 출력에서 ​​파사드만 기능의 표면 레이어라는 것을 알 수 있습니다. 실제 작업은 외부 서비스에서 발생할 수 있으며 매우 간단한 인터페이스를 노출하여 외관 사용자로부터 여전히 추상화됩니다.

    요지는 파사드 패턴입니다 😁

    이 튜토리얼의 모든 코드는 이것this github repo에서 찾을 수 있습니다.

    건배 ☕️

    좋은 웹페이지 즐겨찾기