공부해봅시당

[디자인 패턴] 구조 패턴 - Facade Pattern 본문

STUDY/디자인 패턴

[디자인 패턴] 구조 패턴 - Facade Pattern

tngus 2024. 4. 10. 19:54

1. Facade

Facade는 외관, 즉 건물의 출입구로 이용되는 정면 외벽 부분을 뜻하는 단어이다.

 

건축에서 Facade의 궁극적 목적은 `소통`이다.

건물의 정면만 보더라도 건물이 어떤 목적을 하는지 단번에 알 수 있다는 것이다.

 

그래서 아래와 같은 특징을 가지게 된다.

 

- 건축의 Facade는 사람들이 건물을 쉽게 인식하고 접근할 수 있도록 돕는다.

- 건물의 Facade는 다양한 기능(문, 창문, 장식 등)을 통합적으로 보여주며 건물과 외부 세계 사이의 주요 접점 역할을 한다.

- 건축에서 Facade는 건물의 기능과 성격을 외부에 전달하는 중요한 수단이다.

- 건축의 Facade는 건물의 나머지 부분에 영향을 주지 않고도 변경할 수 있는 유연성을 제공한다.

 

2. Facade Pattern 등장

2-1. 프로그래밍에서는 어쩌다 Facade Pattern이 등장하게 됐을까?

정교한 라이브러리나 프레임워크에 속하는 광범위한 객체들의 집합으로 코드를 작동하게 만들어야 한다고 상상해 보자.

 

일반적으로는 이러한 객체들을 모두 초기화하고, 종속성 관계들을 추적하고, 올바른 순서로 메서드들을 실행하는 등의 작업을 일일이 수행해줘야 한다.

그 결과, 클래스들의 비즈니스 로직이 다른 클래스들의 구현 세부 사항들과 밀접하게 결합되면서 복잡도가 올라가고, 유지 보수와 확장이 상당히 어려워지게 된다.

 

한마디로 복잡성을 관리하기가 굉장히 어려워지는 것이다.

 

그래서 프로그래밍의 라이브러리나 프레임워크에도 Facade, 즉 진입점을 만들어 복잡한 형태를 숨기고 간단하게 확인할 수 있도록 하는 것이다.

 

 

그래서 Facade Pattern은 복잡한 시스템에 대해 단순화된 인터페이스를 제공하는 구조라고 설명한다.

이 패턴의 주된 목적은 복잡한 시스템의 사용을 더 쉽게 만들기 위해 하위 시스템의 복잡성을 클라이언트로부터 숨기는 것이다.

클라이언트는 Facade를 통해 하위 시스템과 소통할 수 있으며, 이를 통해 시스템의 사용성과 접근성이 크게 향상된다.

 

2-2. Facade Pattern 특징

위에서 살펴봤던 Facade의 특징이 Facade Pattern에서도 그대로 반영된다.

Facade의 특징과 비교하여 이해해보자.

 

1) 접근성과 이해의 용이성

- 건축의 Facade는 사람들이 건물을 쉽게 인식하고 접근할 수 있도록 돕는다.

- 프로그래밍의 Facade 패턴은 복잡한 시스템의 사용을 단순화하여 프로그래머가 시스템을 더 쉽게 이해하고 사용할 수 있도록 한다.

2) 통합된 인터페이스 제공

- 건물의 Facade는 다양한 기능(문, 창문, 장식 등)을 통합적으로 보여주며 건물과 외부 세계 사이의 주요 접점 역할을 한다.

- 프로그래밍에서도 Facade 패턴은 여러 하위 시스템의 복잡한 작업을 단일 인터페이스 뒤에 숨겨 사용자가 쉽게 접근할 수 있도록 한다.

3) 소통의 간소화

- 건축에서 Facade는 건물의 기능과 성격을 외부에 전달하는 중요한 수단이다.

- 프로그래밍에서 Facade 패턴은 복잡한 내부 구조를 감추고 필요한 기능만을 노출시켜, 시스템 내부와 외부 간의 소통을 간소화한다.

4) 유연성과 확장성

- 건축의 Facade는 건물의 나머지 부분에 영향을 주지 않고도 변경할 수 있는 유연성을 제공한다.

- 비슷하게, 프로그래밍에서 Facade 패턴은 하위 시스템의 구현 변경이 클라이언트에게 영향을 미치지 않도록 하여 시스템의 유연성과 확장성을 증가시킨다.

 

3. Facade Pattern

퍼사드 패턴(Facade Pattern)은 `사용하기 복잡한 클래스 라이브러리에 대해 사용하기 편하게 간편한 인터페이스(API)를 구성하기 위한 구조 패턴` 이다.

예를 들어 라이브러리의 각 클래스와 메서드들이 어떤 목적의 동작인지 이해하기 어려워 바로 가져다 쓰기에는 난이도가 높을때, 이에 대한 적절한 네이밍과 정리를 통해 사용자로 하여금 쉽게 라이브러리를 다룰수 있도록 인터페이스를 만드는데, 우리가 교제를 보고 필기노트에 재정리를 하듯이 클래스를 재정리하는 행위로 보면 된다.


본래 프로그램이라는 것은 업데이트를 통해 점점 커지게 된다. 버전이 올라갈수록 많은 클래스들이 만들어져 서로 관계를 맺으면서 점점 복잡해지게 된다. 그래서 커다란 솔루션을 구성하려면 상호 관련된 많은 클래스들을 적절히 제어해야 할 필요성이 있다. 이때 이 처리를 개별적으로 제어하는 것이 아닌 일종의 `창구`를 준비하여 중계할 수 있도록 구성해준다면, 사용자는 창구를 통해서 간단한 명령 요구만 내리면 요구에 대해 필요한 모든 집약적 행위들을 창구가 알아서 처리해 결과를 내주게 된다.

 

고객은 복잡한 절차 지식없이 고객센터(창구)에 요구만 하면 결과를 얻는다

 

이처럼 퍼사드(Facade) 패턴은 복잡하게 얽혀 있는 것을 정리해서 사용하기 편한 인터페이스를 고객에게 제공한다고 보면된다. 그래서 고객은 복잡한 시스템을 알 필요없이 시스템의 외부에 대해서 단순한 인터페이스를 이용하기만 하면 된다. 퍼사드를 이용하면 자칫 동작의 목적과 같은 중요한 사항을 놓치는 실수를 줄일 수 있다.

4. Facade Pattern 구조

4-1. 구성

1) Facade

서브시스템 기능을 편리하게 사용할 수 있도록 하기 위해 여러 시스템과 상호 작용하는 복잡한 로직을 재정리해서 높은 레벨의 인터페이스를 구성한다. Facade 역할은 서브 시스템의 많은 역할에 대해 ‘단순한 창구’가 된다. 클라이언트와 서브시스템이 서로 긴밀하게 연결되지 않도록 한다.

 

2) Additional Facade

퍼사드 클래스는 반드시 한개만 존재해야 한다는 규칙같은 건 없다. 연관 되지 않은 기능이 있다면 얼마든지 퍼사드 2세로 분리한다. 이 퍼사드 2세는 다른 퍼사드에서 사용할 수도 있고 클라이언트에서 직접 접근할 수도 있다.

 

3) SubSystem(하위 시스템)

수십 가지 라이브러리 혹은 클래스들

 

4) Client

서브 시스템에 직접 접근하는 대신 Facade를 사용한다.

 

4-2. 재귀적인 Facade 패턴

재귀적 퍼사드란 위에서 언급한 Additional Facade 를 말하는 것이다. 예를 들어 다수의 클래스, 다수의 패키지를 포함하고 있는 큰 시스템에 요소 요소 마다 Facade 패턴을 여기 저기 적용하고 다시 그 Facade를 합친 Facade를 만드는 식으로, 퍼사드를 재귀적으로 구성하면 시스템은 보다 편리하게 된다. 이처럼 퍼사드는 한개만 있으라는 법은 없으며 필요에 의하면 얼마든지 늘려 의존할 수 있다.

 

4-3. 구조 특징

퍼사드 패턴은 패턴이라기 보단 논리에 가깝다.

 

퍼사드 패턴은 전략 패턴이나 팩토리 패턴과 같은 여타 다른 디자인 패턴과는 다르게 클래스 구조가 정형화 되지 않은 패턴이다. 반드시 클래스 위치는 어떻고 어떤 형식으로 위임을 해야되고 이런 것이 없다. 그냥 퍼사드 클래스를 만들어 적절히 기능 집약화만 해주면 그게 디자인 패턴이 되는 것이다.

C언어나 파이썬에서 어떠한 복잡한 로직의 코드가 있으면 이걸 main 함수에서 모두 실행하는 것이 아니라, 함수(function) 분리를 통해 main 함수의 코드를 심플하게 구성해본 경험이 있을 것이다. 이를 객체 지향 프로그래밍 관점으로 치환한 것이 퍼사드 패턴이다. 즉, 퍼사드는 복잡한 것(내부에서 실행되고 있는 많은 클래스의 관계나 사용법)을 단순하게 보여주는 것에 초점을 둔다. 클라이언트로 하여금 복잡한 것을 의식하지 않도록 해주는 것이다. 

Client들은 복잡한 Subsystem을 의식하지않고 Facade라는 창구를 통해 결과를 얻는다

 

5. Facade Pattern 사용 시기와 장단점

5-1. 사용 시기

- 시스템이 너무 복잡할때

- 그래서 간단한 인터페이스를 통해 복잡한 시스템을 접근하도록 하고 싶을때

- 시스템을 사용하고 있는 외부와 결합도가 너무 높을 때 의존성 낮추기 위할때

5-2. 장점

- 하위 시스템의 복잡성에서 코드를 분리하여, 외부에서 시스템을 사용하기 쉬워진다.

- 하위 시스템 간의 의존 관계가 많을 경우 이를 감소시키고 의존성을 한 곳으로 모을 수 있다.

- 복잡한 코드를 감춤으로써, 클라이언트가 시스템의 코드를 모르더라도 Facade 클래스만 이해하고 사용 가능하다. 

외부에서 내부 로직을 직접 사용하기 떄문에 내부 로직의 구조를 변경한다고 하거나 파라미터나 리턴값 등을 변경할 경우 직접적으로 영향을 받아 수정이힘들거나 불가능한 경우가 종종 있다. 하지만 중간에 매개체 역할을 해주는 퍼사드 객체가 있기 때문에 실제 내부 로직이 어떻게 변경이 되더라도 상관이 없어지므로 의존성이 감소된다.

 

5-3. 단점

- 퍼사드가 앱의 모든 클래스에 결합된 God 객체가 될 수 있다

- 퍼사드 클래스 자체가 서브시스템에 대한 의존성을 가지게 되어 의존성을 완전히는 피할 수는 없다.

- 어찌되었건 추가적인 코드가 늘어나는 것이기 때문에 유지보수 측면에서 공수가 더 많이 들게 된다.

- 따라서 추상화 하고자하는 시스템이 얼마나 복잡한지 퍼사드 패턴을 통해서 얻게 되는 이점과 추가적인 유지보수 비용을 비교해보며 결정하여야 한다.

 

6. Facade Pattern 예제 with JAVA

Facade 패턴을 적용한 간단한 Java 코드 예제를 살펴보자.

 

이 예제에서는 컴퓨터 시스템의 시작 과정을 단순화하는 Facade를 구현한다. 컴퓨터의 시작 과정에는 CPU의 초기화, 메모리의 로드, 하드 드라이브의 읽기 등 여러 복잡한 단계가 포함될 수 있지만, Facade 패턴을 사용함으로써 이러한 복잡한 과정을 단순한 인터페이스 뒤에 숨길 수 있다.

 

6-1. 하위 시스템 클래스 정의

컴퓨터의 각 부품(하위 시스템)에 해당하는 클래스를 정의

// CPU
class CPU {
    public void initialize() {
        System.out.println("CPU is initializing...");
    }
}

// Memory
class Memory {
    public void load(long position, byte[] data) {
        System.out.println("Loading data into memory...");
    }
}

// HardDrive
class HardDrive {
    public byte[] read(long lba, int size) {
        System.out.println("Reading data from hard drive...");
        return new byte[]{};
    }
}

 

6-2. Facade 클래스 정의

위에서 정의한 하위 시스템을 사용하여 컴퓨터를 시작하는 과정을 단순화하는 Facade 클래스를 정의

// ComputerFacade 클래스는 컴퓨터의 시작 과정을 단순화합니다.
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;

    public ComputerFacade() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
    }

    // 컴퓨터 시작 과정을 단순화하는 메소드
    public void startComputer() {
        cpu.initialize();
        memory.load(0, hardDrive.read(0, 64));
        System.out.println("Computer started successfully.");
    }
}

 

6-3. Facade 패턴 사용

ComputerFacade 클래스를 사용하여 컴퓨터의 시작 과정을 간단히 호출하는 클라이언트 코드를 작성

public class FacadePatternDemo {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.startComputer();
    }
}

 

7. Facade Pattern 예제 with Springboot

이 예제에서는 간단한 사용자 관리 시스템을 구현해보자

 

유저가 다양한 방법으로 회원가입하는 상황에 대해 예제를 설계할 것이다.

 

일반 회원가입을 하거나, 페이스북이나 구글로 소셜 로그인을 하는 상황을 처리하기 위해 Facade 패턴을 적용해보자.

 

이 예제에서는 사용자 인증 과정의 복잡성을 Facade 뒤에 숨겨서, 컨트롤러 계층에서는 단순화된 인터페이스를 통해 다양한 인증 방식을 처리할 수 있도록 한다.

 

7-1. 모델 클래스 정의

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
    private Long id;
    private String name;
    private String email;
}

 

7-2. Authentication 서비스 인터페이스 및 구현체

일반 회원가입과 소셜 로그인(페이스북, 구글)을 위한 서비스 인터페이스를 정의하고, 각각에 대한 구현체를 제공

public interface AuthenticationService {
    User authenticate(String token);
}

@Service
public class StandardAuthenticationService implements AuthenticationService {
    @Override
    public User authenticate(String token) {
        // 토큰을 사용하여 일반 회원가입 인증 로직 구현
        System.out.println("Authenticating with standard method...");
        return new User(1L, "Standard User", "standard@example.com");
    }
}

@Service
public class FacebookAuthenticationService implements AuthenticationService {
    @Override
    public User authenticate(String token) {
        // 페이스북 토큰을 사용한 인증 로직 구현
        System.out.println("Authenticating with Facebook...");
        return new User(2L, "Facebook User", "facebook@example.com");
    }
}

@Service
public class GoogleAuthenticationService implements AuthenticationService {
    @Override
    public User authenticate(String token) {
        // 구글 토큰을 사용한 인증 로직 구현
        System.out.println("Authenticating with Google...");
        return new User(3L, "Google User", "google@example.com");
    }
}

 

7-3. Authentication Facade 계층 정의

@Component
public class AuthenticationFacade {
    @Autowired
    private StandardAuthenticationService standardAuthenticationService;

    @Autowired
    private FacebookAuthenticationService facebookAuthenticationService;

    @Autowired
    private GoogleAuthenticationService googleAuthenticationService;

    public User authenticate(String method, String token) {
        switch (method.toLowerCase()) {
            case "standard":
                return standardAuthenticationService.authenticate(token);
            case "facebook":
                return facebookAuthenticationService.authenticate(token);
            case "google":
                return googleAuthenticationService.authenticate(token);
            default:
                throw new IllegalArgumentException("Unknown authentication method: " + method);
        }
    }
}

 

7-4. 컨트롤러 계층 정의

@RestController
@RequiredArgsConstructor
public class AuthenticationController {
    private final AuthenticationFacade authenticationFacade;

    @PostMapping("/authenticate")
    public User authenticate(@RequestParam String method, @RequestParam String token) {
        return authenticationFacade.authenticate(method, token);
    }
}

 

 


출처

https://refactoring.guru/ko/design-patterns/facade

 

퍼사드 패턴

/ 디자인 패턴들 / 구조 패턴 퍼사드 패턴 다음 이름으로도 불립니다: Facade 의도 퍼사드 패턴은 라이브러리에 대한, 프레임워크에 대한 또는 다른 클래스들의 복잡한 집합에 대한 단순화된 인터

refactoring.guru

https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%ED%8D%BC%EC%82%AC%EB%93%9CFacade-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90

 

💠 퍼사드(Facade) 패턴 - 완벽 마스터하기

Facade Pattern 퍼사드 패턴(Facade Pattern)은 사용하기 복잡한 클래스 라이브러리에 대해 사용하기 편하게 간편한 인터페이스(API)를 구성하기 위한 구조 패턴 이다. 예를들어 라이브러리의 각 클래스

inpa.tistory.com

https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%82%AC%EB%93%9C

 

파사드 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 성 베드로 대성당의 기념비적인 파사드. 파사드(프랑스어: Façade)는 건물의 출입구로 이용되는 정면 외벽 부분을 가리키는 말이다. 한글화하여 순화하려면 '정

ko.wikipedia.org