728x90
👈 이전글
[NBCAMP | Spring 6기] 60일차 TIL + 싱글톤 패턴
KDT 실무형 스프링 백엔드 엔지니어 양성과정 6기
🗝 오늘의 학습 키워드 : 디자인 패턴
빌더 패턴
옵저버 패턴
📖 공부한 내용 본인의 언어로 정리하기
옵저버 패턴
여러명의 옵저버가 존재
옵저버는 한 곳만 바라보며 Event를 감지 및 반영
구조
Subject(Event) :주체
- 상태가 변할 수 있는 객체, 옵저버 목록을 유지 관리
- 상태 변화가 발생하면 등록된 모든 옵저버에게 알림을 보냄
Observer : 객체
- 주체의 상태 변화를 감지하고 반응하는 객체
- 주체에 등록을 요청하고, 주체로부터 상태 변화 알림을 받으면 특정 행동을 수행
- 옵저버 인터페이스 생성
- update()
- 이벤트가 발생했을 때, 각 클래스에 맞는 작업을 수행
- update()
- Event 안에는 List<Observer>가 있음.
- add()
- 리스트에 Observer 객체를 추가
- notify()
- Event 발생 시, 소유하고 있는 Observer 객체의 update() 메서드를 호출
- add()
예시
여러 객체가 하나의 객체를 관찰하고 그 상태 변화에 따라 동작하도록 할 때 유용하다.
- 뉴스 구독 서비스
- 소셜 미디어의 팔로우 시스템
구현

이벤트에 반응하는 update() 메서드 : 각 옵저버가 어떻게 반응할 지 결정
// Observer 인터페이스
interface Observer {
void update();
}
Observer 인터페이스를 상속받는 강아지와 고양이 클래스 구현
Event 발생 시, Subject가 Observer 객체의 update() 메서드 호출
각 Observer 객체는 울음 소리 출력
// Dog 클래스
Class Dog implements Observer {
public void update() {
System.out.println("멍! 멍!");
}
}
// Cat 클래스
Class Cat implements Observer {
public void update() {
System.out.println("야옹~!");
}
}
주체는 옵저버 리스트와 옵저버를 추가하는 메서드(register()) 옵저버를 업데이트 하는 메서드(notifyObservers())를 가짐
// Owner 클래스(Subject)
Class Owner {
// Observer 객체 리스트
private ArrayList<Obserber> animals = new ArrayList<>();
// Observer 객체 등록 메서드
public void register(Observer animal) {
animals.add(animal);
}
// Observer 객체의 update() 메서드 호출 메서드
public void notifyObservers() {
for (Observer animal : this.animals) {
animal.update();
}
}
}
주체는 Observer를 관리
Event 발생 시, notify() 실행하면 Observer는 update() 실행
장점
- 느슨한 결합 : 서로 독립적으로 수정, 개발
- 확장성 : 새로운 Observer 쉽게 추가
- 재사용성 : 코드 변경하지 않아도 다양한 Observer에 재사용
단점
- 메모리 누수
- 성능 저하
- 너무 많은 Observer가 등록되어 있을 경우,
Event 발생에 대한 notify() 실행이 성능 저하를 가져올 수 있음.
- 너무 많은 Observer가 등록되어 있을 경우,
- 예측 불가능한 업데이트 순서
- Observer의 통제 순서가 구현 방식에 따라 달라질 수 있음, 예측 불가능해질 수 있음
빌더 패턴(Builder Pattern)
Lombok의 @Builder = 심플 빌더 패턴에 대한 설명입니다.
GOF의 디렉터 빌더 패턴 아닙니다.
- 객체 생성에 관련된 디자인 패턴 중 하나
- 복잡한 객체를 단계적으로 생성
- 빌더 패턴을 적용하기 좋은 경우
- 객체 생성에 필요한 필드가 많은 경우
- 생성 과정이 복잡한 경우
- 빌더 패턴을 적용하기 좋은 경우
- 생성 과정을 유연하게 관리
장점
- 필요한 데이터만 설정
- 필수/ 선택적 필드를 쉽게 구분하고 객체 생성
- ex) 햄버거 재료 선택
- 객체 생성의 유연성 향상
- 양상추 대신 피클 넣기
- 생성자를 사용한 경우 >> 수정 필요
- Builder Pattern >> 생성할 때, 양상추를 빼고 피클 추가
- 양상추 대신 피클 넣기
- 가독성
- ex) Burger.builder()
.name("핫 치킨버거")
.patty("chicken")
.cheese(1)
.build();
- ex) Burger.builder()
- 변경 가능성 최소화
- 생성자 혹은 Setter를 사용하지 않기 때문에
객체의 상태가 변경되지 않음. (불변 객체를 쉽게 만들 수 있음) - 안전하게 공유 가능 >> 협업에 사용하기 좋다.
- 생성자 혹은 Setter를 사용하지 않기 때문에
사용방법
- 생성자 위에 @Builder
- 객체 만들기 객체.builder()
- 객체 생성 시, 필수 입력값 추가하는 법
- builder() 메서드를 구현하여 매개변수 값이 null로 오지 않도록 구현
// 필수 입력값을 가진 builder 메서드
public static BurgerBuilder builder(Order order, String name) {
if (order == null || name == null) {
throw new IllegalArgumentException("주문과 버거 이름은 필수입니다.");
}
return new BurgerBuilder().order(order).name(name);
}
// 버거 만들기 필수값 반영
Burger newBurger = Burger.builder(order, "핫 치킨버거")
.patty("chicken")
.cheese(1)
.build();
싱글톤 패턴과 빌더 패턴 차이점
- 싱글톤 패턴
- 인스턴스를 오직 하나만 생성, 전역적으로 접근 가능
- 첫 번째로 필요할 때, 인스턴스 생성
- 하나의 인스턴스만 필요하고 그 인스턴스를 애플리케이션 전체에서 공유하고 싶을 때, 적합
ex) 데이터베이스 연결, 로깅 시스템, 설정 관리 - 변경 불가능한 인스턴스
- 멀티스레드 환경에서 동기화 고려가 필요할 수 있음
- 빌더 패턴
- 빌더를 통해 객체를 생성할 때마다 새로운 객체 생성
- 인스턴스는 필요할 때마다 여러 개 생성 가능
- 복잡한 객체를 단계적으로 생성하고, 필수 및 선택적 매개변수를 유연하게 관리하고자 할 때, 적합
ex) 옵션이 많은 객체 생성 - 불변 객체를 쉽게 만들 수 있음, 설정은 유연하게 가능
- 각 객체는 별도로 생성되므로 멀티스레드 문제 x
⌛ 오늘의 회고
카카오 로그인 구현을 하는데 인가 코드를 받는 곳에서 문제가 생겼다.
팀 프로젝트 시연은 postman으로 하는데
강의에서 카카오로그인을 구현할 때는 프론트단을 만들어 놓은 상태에서 브라우저로 로그인을 했었어서
인가코드를 받아 자동으로 redirectURL로 연결이 되었었는데
postman에서는 그것을 어떻게 처리해야하는지 모르겠는 것이었다.
Kakao developer에서 문서도 찾아 보았지만 인가 코드 없이 하는 방법을 찾지 못했다.
ChatGPT에도 방법이 있는지 물어보았는데 테스트용 엑세스 토큰을 발급받아서
인가코드 받는 부분을 건너뛰고 테스트를 할 수 있는 것 같기도 했지만
튜터님께 여쭤보니 그냥 예전에 만들어 둔 프로젝트를 통해 인가코드를 받아 사용해라고 하셨다.
뭔가 마음에 들지 않는 답변이라 예전 프로젝트의 HTML 파일에서 카카오 로그인에 필요한 부분만 간단히
잘라와서 파일을 만들었다.
다행히 브라우저로 테스트는 잘 되었다.
오후에는 테스트 코드를 작성하였는데 Service단은 테스트 코드를 무난히 작성하였지만
인증, 인가와 관련된 Filter 단이나 Controller는 어떻게 코드를 써야하는지 막막했다.
유튜브도 찾아보고 했지만 난 Bad_Request를 Status로 설정했는데 왜 계속 Forbidden이 뜨는지 모르겠다.ㅜㅜ
💭 내일 학습할 것은 무엇인지
- 테스트 코드 작성하기
👉 다음글
728x90