복잡한 과장을 간단하게 표현하는 퍼사드 패턴
디자인 패턴
만약 이 클래스가 바뀐다면 얼마나 많은 코드를 고쳐야 하는가?
와 같은 확장성(Extensibility) 문제는 많은 디자인 패턴들이 해결하고자 하는 문제 중 하나입니다.
- 디자인 패턴에는 생성, 구조, 행위, 3가지 분류가 있습니다.
- 구조패턴은 적응자, 브리지, 복합체, 장식자, 퍼사드, 플라이급, 프록시로 분류가 됩니다.
- 이중 가장 많이 사용하는 패턴은 적응자, 장식자, 퍼사드, 프로시입니다.
- 문서 프로그램의 경우 플라이웨이트을 사용합니다.
- 게임의 경우에는 프록시와 복합체, 장식자 등이 사용됩니다.
퍼사드 패턴은 구조에 대한 패턴입니다.
- structural patterns
- 클래스나 객체를 조합해 더 큰 구조를 만드는 패턴입니다.
- 구조 패던은 여러 인터페이스를 합성(Composite)하여 서로 다른 인터페이스들의 통일된 추상을 제공합니다.
- 구조 패턴을 사용하면 서로 독립적으로 개발한 클래스 라이브러리를 마치 하나인 것처럼 사용할 수 있습니다.
- 구조 패턴의 가장 중요한 포인트는 인터페이스나 구현을 복합하는 것이 아니라 객체를 합성하는 방법을 제공한다는 것입니다. 이는 컴파일 단계에서가 아닌
런타임 단계
에서 복합 방법이나 대상을 변경할 수 있다는 점에서 유연성을 가집니다.
퍼사드란?
- 프랑스어로 외관(건물의 정면)이라는 뜻입니다.
- 건물의 외벽에서 보면 안의 구조는 보이지 않는다는 특징으로 이름 지어진거 같습니다.
- 키워드 :
단순한 접근
, 분리
퍼사드 패턴
- 퍼사드는 클래스 라이브러리 같은 어떤 소프트웨어의 다른 커다란 코드 부분에 대한 간략화된
인터페이스를 제공하는 객체
입니다.
- 퍼사드는 좋게 작성되지 않은 API의 집합을
하나
의 좋게 작성된 API로 감싸줍니다.
인터페이스를 제공하는 객체
- 한 서브시스템 내의 인터페이스 집합에 대한 획일화된 하나의 인터페이스를 제공하는 패턴으로, 서브시스템을 사용하기 쉽도록 상위 수준의 인터페이스를 정의합니다.
- 개발자들에게 복잡해진 각각의 클래스들을 다 이해하면서 서브시스템을 사용하기란 어려운 일입니다. 이럴 때 퍼사드 패턴은 서브시스템에 대한 단순하면서도 기본적인 인터페이스를 제공함으로써 대부분의 개발자들에게 적합한 클래스 형태를 제공합니다.
시스템과 시스템 간 의존관계 완화
- 퍼사드는 인터페이스를 단순화 시킬 뿐 아니라 클라이언트와 구성요소들로 이루어진 서브시스템을
분리
시키는 역할도 합니다.
- 단순한 형태로 통합하여 제공하고 나머지 부분은 내부적으로 처리함으로써 사용자와 서브시스템 사이의
호출 횟수가 감소
하게 되는 효과가 있습니다.
- 의존성이 낮아지고 유연성이 향상되어 관리가 용이해집니다.
간단한 인터페이스를 제공함으로써 최소 지식 원칙
을 준수하는 것에 도움을 줍니다.
최소 지식 원칙(Principle of Least Knowledge)
- 데메테르의 원칙(Law of Demeter)
- 정말 친한 친구하고만 이야기 하는 것을 말합니다.
- 이 원칙을 잘 따르면 객체들 사이의 의존성을 줄일 수 있고, 소프트웨어 관리가 더 용이해질 수도 있습니다.
- 하지만 이 원칙을 적용하다 보면 다른 구성요소에 대한 메소드 호출을 처리하기 위해
래퍼 클래스
를 더 만들어야 할 수도 있습니다. 그러다 보면 시스템이 더 복잡해지고, 개발 시간도 늘어나고, 성능이 떨어질 수도 있습니다.
최소 지식 원칙을 지키는 방법
- 아래의 종류의 메소드만을 호출하면 이 원칙을 지킬 수 있습니다.
- 객체자체
- 메소드에 매개변수로 전달된 객체
- 그 메소드에서 생성하거나 인스턴스를 만든 객체
- 그 객체에 속하는 구성요소
장점
- 퍼사드(facade) 패턴을 이용하면 분할 된 소프트웨어의 유지보수 용이성이 향상 됩니다.
- 퍼사드는 소프트웨어 라이브러리를 쉽게 이해하고 사용 할 수 있게 해줍니다.
- 퍼사드는 라이브러리를 사용하는 코드들을 읽기 쉽게 해줍니다.
- 서브시스템 내부 설계의 변경이 다른 서브시스템에 독립적으로 자유롭게 될 수 있습니다.
사용처
- 퍼사드 패턴은 특정 기능에 대해 인터페이스의 수가 확장되고, 시스템이 복잡해질 수 있는 상황에서 사용하기 적합합니다.
- 퍼사드 패턴은 비슷한 작업을 해야하는 다양한 인터페이스들 중 하나의 인터페이스를 클라이언트에 제공해야 할 때 적용하는 것이 좋습니다.
- 팩토리 패턴과 종종 함께 사용됩니다.
주의점
- 퍼사드 패턴은 클라이언트 어플리케이션의 헬퍼 역할을 하는 것이지, 서브시스템 인터페이스를 숨기는 것은 아닙니다.
- 다른 메소드를 호출하기 위한 래퍼클래스를 만들어야 하는 등의 단점도 생길 수 있습니다.
UML
class User {
constructor(name, age, grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
getMoney(amount) {
let permissionDenied = '권한이 없습니다.';
if (!new Grade(this.grade).check() || !new Age(this.age).get()) {
return permissionDenied;
}
const money = new Money().get();
return `${this.name}님은 ${money}원 있습니다.`;
}
}
class Grade {
constructor(grade) {
this.grade = grade;
}
check() {
return this.grade > 1;
}
}
class Age {
constructor(age) {
this.age = age;
}
get() {
return this.age > 14;
}
}
class Money {
constructor() {}
get() {
return 2021;
}
}
const user = new User('yuni', 15, 2);
const result = user.getMoney();
console.log(result);
const user2 = new User('yuni', 13, 1);
const result2 = user2.getMoney();
console.log(result2);
const module = (function () {
const _private = {
i: 5,
get: function () {
console.log(`current value ${this.i}`);
},
set: function (val) {
this.i = val;
},
run: function () {
console.log('running');
},
jump: function () {
console.log('jumping');
},
};
return {
facade: function (args) {
_private.set(args.val);
_private.get();
if (args.run) {
_private.run();
}
},
};
})();
module.facade({ run: true, val: 10 });
유사한 패턴과의 차이점
- 데코레이터 : 한 인터페이스를 다른 인터페이스로 변환합니다.
- 어댑터 : 인터페이스는 바꾸지 않고 책임(기능)만 추가합니다.
- 퍼사드 : 인터페이스를 간단하게 바꿔줍니다.
어댑터와의 차이
- 퍼사드와 어댑터는 모두 여러 개의 클래스를 감쌀 수 있습니다. 하지만 퍼사드는 인터페이스를 단순화시키기 위한 용도로 쓰이는 반면, 어댑터는 인터페이스를 다른 인터페이스로 변환하기 위한 용도로 쓰입니다.
- Mediator 패턴과 혼동될 수 있지만, Facade 패턴은 기능만을 모아둔 구조이고, Mediator 패턴은 복잡한 기능을 제어어하기 위한 행위(상호작용)패턴이다.
- Facade 패턴은 검색 요청을 위해 복잡한 과정을 거쳐야 하는 경우에 여러 개의 클래스들이 밀접한 관계를 가지고 대표 클래스를 통해 원하는 기능을 제공할 수 있도록 해줍니다.
참고