[디자인 패턴] Facade Pattern

전성훈·2023년 11월 3일
0

DesignPattern

목록 보기
11/18
post-thumbnail

주제: 인터페이스 제공


Facade Pattern(외관 패턴)은 소프트웨어 공학 디자인 패턴 중 하나이다. 객체 지향 프로그래밍 분야에서 자주 쓰인다. Facade는 "건물의 정면"을 의미한다. 퍼사드는 클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된 인터페이스를 제공하는 객체이다.

퍼사드 패턴이란

  • 복잡한 시스템에 대한 간단한 인터페이스를 제공하는 디자인 패턴이다. 이 패턴은 클라이언트와 복잡한 시스템 사이에 '퍼사드'라는 단일 클래스를 두어, 클라이언트가 시스템의 복잡성을 직접 다루지 않아도 되게 한다.
  • 즉, 여러 인스턴스를 소유하여 사용해야하는 타입이 있는 경우, 쉽고 간단한 인터페이스를 이용해서 인스턴스들이 일을 하게끔 하고 싶을 경우에 좋은 솔루션이 될 수 있다. 이때 Facade Pattern을 사용하면 인스턴스와 인스턴스 간의 협력이 많아짐에 따라 발생하는 높은 의존관계를 줄이고, 그렇게 시스템 개발의 유연성을 향상시킬 수 있다는 장점이 따른다.

퍼사드 패턴의 구조

facade

  • Facade
    • 클라이언트가 사용할 간단한 인터페이스를 제공한다. 이 클래스는 시스템의 복잡한 부분을 캡슐화하고, 클라이언트의 요청을 적절한 시스템 컴포넌트에 전달한다.
  • Subsystem Classes
    • 시스템의 복잡한 부분을 구현하는 클래스들이다. 이들은 퍼사드에 의해 직접 호출되지만, 퍼시드 없이도 독립적으로 기능할 수 있다.

장단점

장점

  • 시스템의 복잡성을 감춤으로써 클라이언트 코드를 단순화한다.
  • 시스템의 구현과 클라이언트 코드 사이의 결합도를 줄여, 시스템 변경에 대한 영향을 최소화한다.

단점

  • 퍼사드 클래스가 너무 많은 책임을 가지게 되면, 복잡성이 증가할 수 있다.

결론

  • 일반적으로 앱 개발 초기 단계에는 설계를 단순하게 구성하고, 확장을 할 때에도 단순화하기 위해 노력하기 때문에 Facade Pattern을 사용하기가 애매한 경우가 있다. 또한 Facade 패턴을 사용하기 위해 새로운 계층이 추가되면 관리할 타입이 하나 더 생성된다는 단점이 있기도 하다.

예시 코드

Computer라는 타입의 프로퍼티로서 모두 초기화되어 관리하는 방식

import UIKit

protocol Facade {
    func work()
}

struct CPU {
    func work(with menory: Memory) { }
}

struct Memory {
    func input(from devices: [Device]) { }
    func output(to devices: [Device]) { }
}

class Device { }
class InputDevice: Device { }
class OutputDevice: Device { }
class Keyboard: InputDevice { }
class Monitor: OutputDevice { }
class TouchBar: Device { }

struct Computer: Facade {
    private let cpu = CPU()
    private let memory = Memory()
    private let keyboard = Keyboard()
    private let monitor = Monitor()
    private let touchBar = TouchBar()
    
    func work() {
        memory.input(from: [keyboard, touchBar])
        cpu.work(with: memory)
        memory.output(to: [monitor])
    }
}


let computer = Computer()
computer.work()

이미지를 로드하는 작업을 수행하는 API를 감싸는 방식

import UIKit

// Subsystem
class NetworkManager {
    func requestData(from url: URL, completion: @escaping (Data?, Error?) -> Void) {
        // Network request logic
    }
}

// Subsystem
class CacheManager {
    func cache(data: Data, for url: URL) {
        // Cache data logic
    }
    
    func getCachedData(for url: URL) -> Data? {
        // Get cached data logic
    }
}

// Facade
class ImageLoader {
    private let networkManager = NetworkManager()
    private let cacheManager = CacheManager()

    func loadImage(from url: URL, completion: @escaping (UIImage?) -> Void) {
        if let cachedData = cacheManager.getCachedData(for: url), let image = UIImage(data: cachedData) {
            completion(image)
        } else {
            networkManager.requestData(from: url) { data, error in
                guard let data = data, error == nil else {
                    completion(nil)
                    return
                }
                self.cacheManager.cache(data: data, for: url)
                let image = UIImage(data: data)
                completion(image)
            }
        }
    }
}

// Client
let url = URL(string: "https://example.com/image.png")!
let imageLoader = ImageLoader()
imageLoader.loadImage(from: url) { image in
    // Use the image
}

출처(참고문헌)

제가 학습한 내용을 요약하여 정리한 것입니다. 내용에 오류가 있을 수 있으며, 어떠한 피드백도 감사히 받겠습니다.

감사합니다.

0개의 댓글

관련 채용 정보