반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- SQL
- 필드 주입
- DI
- resultMap
- 스프링 빈
- 스프링 부트 입문
- 스프링 컨테이너
- 스프링 부트
- db
- 싱글톤
- jdbc
- 스프링 프레임워크
- kafka
- DIP
- 스프링
- 스프링 부트 기본
- java
- Javascript
- thymeleaf
- 생성자 주입
- JPA
- 스프링부트
- springboot
- spring
- Effective Java
- sqld
- assertThrows
- assertThat
- @Configuration
- mybatis
Archives
- Today
- Total
선 조치 후 분석
[Design Pattern] 구조패턴 - Facade 본문
728x90
반응형
SMALL
퍼사드 (Facade) 패턴
- 복잡한 서브 시스템의 의존성을 최소화하기 위한 목적을 가지는 패턴
- 클라이언트가 사용해야 하는 복잡한 서브 시스템의 의존성을 간단한 인터페이스로 추상화할 수 있다고 한다.
- 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공
- 퍼사드 패턴의 궁극적인 목표는 '객체 간의 의존성을 느슨하게 만드는 것'이다
퍼사드 (Facade) 패턴을 사용하기 좋은 시기
- 시스템이 너무 복잡할 때
- 간단한 인터페이스를 통해 복잡한 시스템을 접근하도록 하고 싶을 때
- 시스템을 사용하고 있는 외부와 결합도가 너무 높을 때, 의존성을 낮추기 위할 때
- Facade : 서브시스템 기능을 편리하게 사용할 수 있도록 하기 위해 여러 시스템과 상호 작용하는 복잡한 로직을 재정리해서 높은 레벨의 인터페이스를 구성한다. Facade 역할은 서브 시스템의 많은 역할게 대해 '창구'가 된다.
- 클라이언트와 서브시스템이 서로 긴밀하게 연결되지 않도록 한다.
- Additional Facade : 퍼사드 클래스는 반드시 한 개만 존재해야 한다는 규칙 같은 건 없다. 연관되지 않은 기능이 있다면 얼마든지 Facade 2세로 분리한다. 이 Facade 2세는 다른 Facade에서 사용할 수도 있고 클라이언트에서 직접 접근할 수 도 있다.
- SubSystem : 여러 개의 라이브러리 혹은 클래스들
- Client : 서브 시스템에 직접 접근하는 대신 Facade를 사용

퍼사드 (Facade) 패턴 적용 전
- DB로부터 값을 얻어와 화면에 데이터를 출력하려는 프로그램이 있다고 가정
- 패키지에는 총 4개, Cache, DBMS, Row, Message 클래스가 존재
작업순서
- DBMS를 조회하기 전에 저장된 Cache를 먼저 확인
- Cache에 데이터가 없으면 DBMS 통해서 조회
- Cache에 데이터가 있으면 가공하고 출력
- 조회된 데이터를 가공하고 출력하고 Cache에 저장
@AllArgsConstructor
@NoArgsConstructor
public class DBMS {
// DB역할을 하는 클래스
private HashMap<String, Row> db = new HashMap<>();
public void put(String name, Row row) {
db.put(name, row);
}
public Row query(String name) {
try {
Thread.sleep(500); // 0.5초 대기 구현
}catch (InterruptedException e) {
}
return db.get(name);
}
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Row {
// DBMS에 저장된 데이터 클래스
private String name;
private String age;
private String email;
}
public class Cache {
//DB에서 조회된 데이터를 임시 저장해주는 Cache
private HashMap<String, Row> cache = new HashMap<>();
public void put(Row row) {
cache.put(row.getName(), row);
}
public Row get(String name) {
return cache.get(name);
}
}
@NoArgsConstructor
@AllArgsConstructor
public class Message {
// Row클래스를 출력하는 클래스
private Row row;
public String nmakeName() {
return "Name : \"" + row.getName() + "\"";
}
public String makeAge() {
return "Age : \"" + row.getAge() + "\"";
}
public String makeEmail() {
return "Email : \"" + row.getEmail() + "\"";
}
}
- 패키지의 코드를 그대로 메인 로직에 작성하여 구현하고 있다. 데이터 조회부터 출력까지 여러 개의 객체가 사용된다.
- 수정이나 확장에 있어 개발자가 실수를 할 수 있는 가능성이 많다.
@Test
void test1() {
// DB 생성 등록
DBMS dbms = new DBMS();
dbms.put("A", new Row("A", "010-1234-5678", "A@nver.com"));
dbms.put("B", new Row("B", "010-2345-5678", "B@nver.com"));
dbms.put("C", new Row("C", "010-3678-5678", "C@nver.com"));
//Cache생성
Cache cache = new Cache();
// DB를 조회하기 전, Cache 먼저 확인
String name = "A";
Row row = cache.get(name);
// Cache 데이터 존재유무 확인
if(row == null) {
row = dbms.query(name);
if(row != null) { // 조회된 데이터가 있으면 Cache에 저장
cache.put(row);
}
}
// dbms에 조회된 데이터 확인
if(row != null) {
Message message = new Message(row);
System.out.println(message.nmakeName());
System.out.println(message.makeAge());
System.out.println(message.makeEmail());
}else {
System.out.println(name + " 가 DB에 존재하지 않음.");
}
}
퍼사드 (Facade) 패턴 적용 후
- 퍼사드 (Facade) 패턴은 다른 디자인 패턴과는 다르게 클래스 구조가 정형화되지 않은 패턴이다.
- 반드시 클래스 위치가 어떻고 어떤 형식으로 위임을 해야 된다는 것이 없다.
- 퍼사드 (Facade) 클래스를 만들어 적절히 기능 집약화만 해주면 그게 디자인 패턴이 된다.
- 단순화된 인터페이스를 통해 서브 클래스를 다룸으로써 개발자의 실수를 줄이고자 하는 것이 퍼사드 (Facade) 패턴
public class Facade {
private DBMS dbms = new DBMS();
private Cache cache = new Cache();
public void insert() {
dbms.put("A", new Row("A", "010-1234-5678", "A@nver.com"));
dbms.put("B", new Row("B", "010-2345-5678", "B@nver.com"));
dbms.put("C", new Row("C", "010-3678-5678", "C@nver.com"));
}
public void run(String name) {
Row row = cache.get(name);
// 캐시에서 확인
if(row == null) {
row = dbms.query(name); // DB에 해당 데이터를 조회해서 row에 저장
if(row != null) { // 조호된 데이터가 있다면 캐시에 저장
cache.put(row);
}
}
// 조회된 row 값이 있으면 출력
if(row != null) {
Message message = new Message(row);
System.out.println(message.nmakeName());
System.out.println(message.makeAge());
System.out.println(message.makeEmail());
}else { // 조호된 내용이 없을 때
System.out.println(name + " 가 DB에 존재하지 않습니다.");
}
}
- 퍼사드 (Facade) 패턴을 적용하니 로직이 훨씬 간결해졌다.
- 퍼사드 (Facade) 패턴의 핵심은 인터페이스(Api)를 적게 구성하는 것
- 라이브러리에서 제공하는 클래스나 메소드가 많이 보이면, 프로그래머는 무엇을 사용하면 좋을지 생각하게 되고
순서도 doc을 살펴보며 확인해야 한다.
@Test
void test2() {
// 퍼사드 (Facade) 객체 생성
Facade facade = new Facade();
// db에 insert
facade.insert();
// 퍼삳드를 통해 캐시, DB 조회 그리고 출력을 한번에 실행
String name = "A";
facade.run(name);
}
퍼사드(Facade)는 서브 클래스들의 캡슐화를 하는 것이 아니다.
서브 클래스들을 사용할 간단한 인터페이스를 제공할 뿐이다.
사용자가 서브 시스템 내부의 클래스를 직접 사용하는 것을 제한할 수는 없다.
그래서 추상화에 가깝다고 볼 수 있다.
※ 보통 퍼사드 (Facade) 객체는 하나만 있어도 충분하므로 싱글톤으로 구성해 주면 좋다.
퍼사드 (Facade) 패턴
장점
- 서브 시스템의 복잡성에서 코드를 분리하여, 외부에서 시스템을 사용하기 쉬워진다.
- 서브 시스템 간의 의존 관계가 많을 경우 이를 감소시키고 의존성을 한 곳으로 모을 수 있다.
- 복잡한 코드를 숨기고, 클라이언트가 시스템의 코드를 몰라도 Facade 클래스만 이해하면 사용 가능하다.
단점
- Facade가 앱의 모든 클래스에 결합된 God 객체가 될 수 있다.
- Facade 클래스 자체가 서브 시스템에 대한 의존성을 가지게 되어 의존성을 완전히 피할 순 없다.
- 추가적인 코드가 생겨나기에 유지보수 측면에서 공수가 발생
- 추상화하고자 하는 시스템이 얼마나 복잡한지 Facade 패턴을 통해서 얻게 되는 이점과 추가적인
유지보수 비용을 비교해 보면서 결정 필요.
728x90
반응형
LIST
'Language > Design Pattern' 카테고리의 다른 글
[Design Pattern] 행동패턴 - Command (0) | 2023.11.01 |
---|---|
[Design Pattern] 구조패턴 - Flyweight (0) | 2023.10.30 |
[Design Pattern] 구조 패턴 - Decorator (0) | 2023.10.27 |
[Design Pattern] 구조 패턴 - Composite (1) | 2023.10.26 |
[Design Pattern] 구조 패턴 - Bridge (0) | 2023.10.25 |