클래스에서 메서드를 유심히 살펴보자.
메서드가 책임지는 액터가 누구인가? 해당 메서드를 사용하는 액터를 생각해보자. 만일 메서드의 액터가 겹친다면 단일책임원칙(SRP)을 위배한 것이다. 또한 메서드의 액터가 다수 집단이라면, 특정 집단에게 제공되는 서비스가 다른 집단에게도 중복으로 제공될 수 있다.(우발적 중복) 또한 해당 메서드를 사용하는 액터들이 메서드를 수정한다면, 병합이 발생할 수 있다.
│퍼사드
소프트웨어 관점에서 '재택근무'는 단일책임 원칙을 위배한다.
부동산을 크게 상업과 주거공간으로 분류한다면, 주택은 상업, 주거를 모두 지원한다. 그리고 기본적으로 '주택'은 상업과 주거를 동시에 만족시킬 수 있다. 또, 동시에 주택은 변경에 취약하다. 가령, 재택근무를 위해 침대를 없애버렸다면, 주거활동이 침해를 받는다. 반면, 오피스 빌딩은 한 가지 활동에 대해서만 책임을 갖기때문에 액터가 주거에 관한 어떠한 변경을 하건 상관없다.
비용문제를 감안해야겠지만 오피스, 주거공간을 따로 분리하는 인터페이스가 바로 퍼사드 패턴의 핵심이다.
퍼사드 패턴은 여러 액터를 책임지고 있는 메서드를 독립적인 클래스로 분리시킨 후, 이를 인터페이스에 연결하는(집합) 방법이다. 아래 다이어그램에서 퍼사드 클래스는 인터페이스 역할을 한다. 퍼사드는 독립시킨 메서드 클래스들을 소환하는 일종의 마법사로 생각할 수 있다.
카페를 퍼사드 패턴으로 정리해보자.
위의 다이어그램에서 클라이언트는 액터가 되며, '카페사장', '직원', '손님'으로 바뀔 수 있다. 그리고 액터들은 '커피 주문하기' 메서드(order)를 통해 커피를 주문할 수 있다. 모든 액터는 CafeFacade인터페이스에서 order()메서드만 실행할 수 있다. 여기서 CafeFacade인터페이스는 커피주문 시스템의 진입로 역할을 한다. 만일 CafeFacade인터페이스가 없다면, 액터에 따라 CoffeeMenu(), Pay()메서드가 직접적으로 연결될 위험이 있고, 여러 액터를 동시에 책임지는 메서드가 탄생할 수도 있다. 이는, 단일책임원칙을 위배한다.
하지만 위와 같이 퍼사드 패턴을 사용한다면, CoffeeMenu(), Pay() 각각의 기능을 담당하는 클래스는 client가 누구인지 알지 못한다.(의존관계 없음) 이렇게 각각의 기능을 클래스로 분리하고, 하나의 인터페이스로 묶는 효과는 크다. 액터의 변경에 유연한 설계가 되기 때문이다. 액터에 따라 각 메서드(인터페이스에 연결된 클래스)를 변경하더라도 다른 액터의 아웃풋이 훼손되지 않는다.
가령, 퍼사드 인터페이스와 분리된 클래스들이 없다면, '카페사장'이란 액터가 계산(Pay()메서드)을 공짜로 변경이라도 하는 날에는 대혼란이 발생한다. 나머지 2명의 액터 역시 공짜로 커피를 주문할 수 있기 때문이다. order()메서드를 퍼사드 패턴으로 변경하지 않는다면, order()메서드는 '카페사장', '직원', '손님' 3명의 액터에 대한 책임을 져야한다.
퍼사드 패턴은 단일책임원칙을 지킬 수 있는 해결책이며, '액터에 따라 변경될 수 있는 자질구레한 기능'이 많을 경우 적절하게 분리하여 하나의 큰 명령어로 묶는 식으로 사용할 수 있다. 반면, 액터가 아닌 가장 하위레벨에서부터 자질구레한 변경이 발생한다면, 어떻게해야 할까?
│미디에이터
미디에이터 패턴은 '행위'를 통해 변경에 대응한다.(퍼사드:구조) 글 첫머리에 소개한 재택근무와 사무실을 다시 생각해보자. 퍼사드는 빌딩, 주택과 같은 전체적인 큰 구조를 통해 책임을 분리했다. 그런데 사무실에서도 잠을 자고, 밥을 먹고, 게임을 하는 등 주거공간처럼 행동하는 직원이 있다면 이를 어떻게 분리해야할까?
구글과 같은 회사는 '구조'로써 사무실과 재택을 구분하기 힘들다. 분명 사무실 빌딩이지만 직원의 '행동'에 따라 주거공간처럼 변할 수 있고, 또 사무공간으로도 변경된다. 이렇게 액터의 행위에 따라 변경이 발생해야하는 상황을 설계할 때 필요한 패턴이 바로 '미디에이터'이다.
위의 다이어그램에서 IMediator는 말 그대로 중간자, 매니저 역할을 한다. IMediator를 상속받은 clientMediator에서 발생한 이벤트(추가,변경)에 따라 createColleague, collegueChanged를 IColleague(추상클래스)에 넘겨준다. 이때 clientMediator는 취미, 업무의 자세한 사항은 알 수 없다. 결과()메서드를 통해 취미, 업무의 결과사항만 알 수 있고, ICollegue 인터페이스에 의존한다.
결론적으로 미디에이터는 빈번한 변경이 발생하는 상황에서도 변경행위에 관한 책임범위를 정확히 분류할 때 사용할 수 있다. 반면, 퍼사드는 구조로써 변경 자체를 원천 차단하는 용도로 사용한다.
'코드 스터디' 카테고리의 다른 글
커맨드 패턴 (0) | 2020.12.09 |
---|---|
탬플릿 매서드, STRATEGY 패턴 [행위] (2) | 2020.12.08 |
소프트웨어 설계5원칙 『의존성역전 DIP』 (0) | 2020.12.04 |
소프트웨어 설계4원칙 『인터페이스 분리 ISP』 (0) | 2020.12.02 |
소프트웨어 설계3원칙 『리스코프 치환 LSP』 (0) | 2020.11.30 |
댓글