Swift/Design_Pattern

[Swift 디자인 패턴] Facade Pattern (퍼사드) - 디자인 패턴 공부 11

Dev_Pingu 2021. 5. 21. 00:15
반응형

안녕하세요 Pingu입니다. 🐧

 

지난 글에서는 구조 패턴 중 Decorator Pattern(데코레이터)에 대해 알아봤는데요, 이번 글에서는 계속해서 구조 패턴 중 하나인 Facade Pattern(퍼사드)에 대해 알아보도록 하겠습니다.

퍼사드 패턴이란?

퍼사드 패턴은 라이브러리, 프레임워크, 혹은 복잡한 클래스들의 집합에 대한 단순화된 인터페이스를 제공하는 디자인 패턴입니다. 하나의 시스템을 서브 시스템들의 조합으로 구성하면 복잡성을 줄이는데 도움이 됩니다. 이러한 설계의 목표는 서브 시스템 간 통신 및 종속성을 최소화하는 것인데요, 이를 위한 방법으로 서브 시스템의 기능을 단순한 인터페이스를 제공하는 퍼사드 객체를 사용하는 것입니다.

  • Facade
    • 어떤 Subsystem 클래스가 클라이언트의 요청에 응답해야 하는지 알고 있습니다.
    • 클라이언트의 요청을 적절한 Subsystem에게 전달합니다.
  • Subsystem
    • Subsystem 기능을 구현합니다.
    • Facade 객체에서 전달받은 요청을 처리합니다.
    • 서브 시스템 클래스들은 Facade 객체의 존재를 모릅니다.
  • Client
    • 클라이언트는 서브 시스템 객체를 직접 호출하는 대신 Facade를 사용합니다.

퍼사드 패턴은 언제 쓰나요?

여러 구성 요소로 구성된 시스템이 있을 때 사용자가 복잡한 작업을 수행하기 위한 간단한 방법을 제공하고 싶을 때 퍼사드 패턴을 사용할 수 있습니다. 예를 들어 쇼핑몰 시스템이 있다고 해볼게요. 쇼핑몰 시스템에는 고객 정보, 상품 정보, 재고 정보, 배송 주문 등 다양한 작업들이 존재할 거예요. 개발자는 소비자에게는 이러한 구성요소 간 관계를 이해할 필요 없이 단순하게 상품을 주문할 수 있도록 만들어줘야 합니다. 이럴 때 퍼사드 패턴을 사용할 수 있습니다.

 

퍼사드는 복잡한 하위 시스템들에 대한 간단한 인터페이스를 제공해주는 클래스입니다. 하위 시스템들을 직접 사용하는 것보다는 제한적인 기능만 제공할 수 있지만 제공하는 기능들은 클라이언트에게 꼭 필요한 기능들을 제공해줍니다.

 

정리하면 아래와 같은 상황에서 Facade 패턴을 사용할 수 있습니다.

  • 서브 시스템을 계층화하고 싶을 때
  • 복잡한 서브 시스템들을 간단하게 사용하기 위한 인터페이스를 만들고 싶을 때

퍼사드 패턴의 결과

장점

  • 서브 시스템의 복잡성으로부터 코드를 분리할 수 있습니다.
  • 서브 시스템으로부터 클라이언트를 보호하고 클라이언트가 서브 시스템을 사용하기 쉽게 만들어줍니다.
  • Facade를 사용하여 시스템과 객체 간 종속성을 계층화할 수 있습니다.
  • 컴파일 종속성을 줄여 서브 시스템이 변경될 때 컴파일 시간을 줄여줍니다.

단점

  • Facade는 앱의 모든 클래스에 결합된 객체가 될 수 있습니다.

예제

그럼 이제 Facade Pattern을 Swift로 구현해보겠습니다.

아까 예로 들었던 쇼핑몰 시스템을 한 번 구현해볼게요!

 

쇼핑몰에는 Customer, Product 객체가 존재합니다.

struct Customer {
    let identifier: String
    var name: String
    var address: String
}

extension Customer: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
    static func == (lhs: Customer, rhs: Customer) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}
struct Product {
    let identifier: String
    var name: String
    var cost: Int
}

extension Product: Hashable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
    static func == (lhs: Product, rhs: Product) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

그리고 쇼핑몰 시스템에는 재고 관리를 위한 기능과 손님들의 주문 현황을 알기 위한 기능이 존재할 거예요.

// 재고 관리
class AvailableProduct {
    var productList: [Product: Int] = [:]
    
    init(productList: [Product: Int]) {
        self.productList = productList
    }
}
// 주문 현황
class OrderList {
    var orderList: [Customer: [Product]] = [:]
}

그럼 이제 이러한 4개의 서브 시스템들을 가지고 주문을 위한 Facade를 만들어 보겠습니다.

주문하는 로직은 아래와 같습니다.

  • 손님의 이름과 손님이 주문한 상품의 이름을 출력합니다.
  • AvailableProduct 객체에 해당 상품의 재고가 존재하는지 확인합니다.
  • 만약 재고가 없다면 재고가 없다고 출력합니다.
  • 재고가 있다면 재고를 한 개 줄이고 OrderList에 해당 정보를 추가합니다.
  • 주문이 완료되었다고 출력합니다.

이를 Facade로 구현하면 아래와 같습니다.

class OrderFacade {
    let productDB: AvailableProduct
    let orderDB: OrderList
    
    init(availableProduct: AvailableProduct, orderList: OrderList) {
        self.productDB = availableProduct
        self.orderDB = orderList
    }
    
    func order(product: Product, customer: Customer) {
        print("\(customer.name)님이 \(product.name)를 주문하셨습니다.")
        if let count = self.productDB.productList[product] {
            if count == 0 {
                print("\(product.name) 재고가 없습니다.")
            } else if count > 0 {
                self.productDB.productList[product] = count - 1
                
                var orderList = self.orderDB.orderList[customer, default: []]
                orderList.append(product)
                self.orderDB.orderList[customer] = orderList
                print("\(customer.name)님의 \(product.name)를 주문 접수 완료!")
            }
        } else {
            print("존재하지 않는 제품입니다.")
        }
    }
}

그럼 이제 실제로 사용해보겠습니다.

위와 같이 상품들과 손님 객체를 만들어 Facade 객체를 만듭니다. 그런 뒤 Facade 객체의 메서드를 사용하여 손쉽게 물건을 주문하는 것을 볼 수 있어요. 이렇게 다양한 서브 시스템들을 쉽게 사용할 수 있도록 만들어주는 것이 Facade Pattern이라고 할 수 있습니다.

 

이렇게 구조 패턴 중 하나인 Facade Pattern에 대해 알아보고 간단하게 구현도 해봤습니다

혹시라도 틀린 부분이 있다면 알려주시면 감사하겠습니다.

 

전체 코드는 여기에서 볼 수 있습니다.

 

감사합니다!

반응형