프로그래밍에서 공통적인 문제를 쉽게 해결하기 위해 만들어진 가이드라인을 디자인 패턴(Design Pattern)이라고 합니다. 라이브러리처럼 실제 코드를 제공하지는 않지만, 특정 유형의 문제를 해결하는 방식을 제공합니다. 수학으로 비유해 보자면 '공식'이죠. 프로그래밍 전문가들의 땀과 눈물로 만들어진 결과물이라고 할 수 있겠습니다.
디자인 패턴으로 잘 알려진 감마 외 3인(Gang of Four, GoF)이 쓴 디자인 패턴 책에서는 23가지 기본 디자인 패턴을 소개하고 있습니다. 그러나 이번 포스팅에서는 주로 사용되는 싱글톤, 빌더, 옵저버 패턴에 대해 알아보겠습니다.
왜 디자인 패턴이 필요한가?
1. 재사용성: 디자인 패턴을 사용함으로써 개발자는 문제가 발생할 때마다 코드를 다시 구현하는 대신 기존 솔루션을 활용할 수 있습니다.
2. 유지보수성: 문제를 해결하는 표준 방법을 제공하여 코드를 보다 유지보수하기 쉽게 만듭니다. 개발자는 해당 패턴에 익숙하므로(학습을 하였다면) 코드를 이해하고 수정하기가 더 쉽습니다.
3. 모범 사례: 일반적인 문제에 대한 모범 사례와 검증된 해결책을 기반으로 만들어 졌습니다. 해당 패턴을 채택함으로써 문제에 대한 효과적이고 효율적인 솔루션을 사용할 수 있습니다.
싱글톤 패턴
싱글톤 패턴은 클래스의 인스턴스 갯수가 두 개 이상이 되지 않도록 만드는 패턴입니다. 즉, 하나의 클래스에는 최대 한 개의 인스턴스 만이 존재해야 된다는 것이죠. 이제 싱글톤 자바 샘플 코드를 살펴볼까요?
그림 1-1에서 Singleton 클래스의 생성자는 다른 클래스가 Singleton 클래스의 새로운 인스턴스를 생성하지 못하도록 private 접근 제한자를 가지고 있습니다. 그리고 단일 인스턴스를 보유하도록 하는 정적 필드인 'instance'도 있습니다.
getInstance 메서드를 호출하면, instance 필드가 null인지 확인하고 null이면 Singleton 클래스의 새 인스턴스를 생성합니다. 그렇지 않으면 단순히 기존의 인스턴스를 반환합니다.
이 Singleton 클래스를 사용하려면 getInstance 메서드를 호출하면 됩니다.
Singleton 클래스의 생성자가 private이기 때문에 생성자로는 인스턴스를 만들 수 없습니다. 정의해 두었던 getInstance 메서드를 사용하여 인스턴스를 두 번 생성하였습니다.
singleton2, singleton3 객체 모두 동일한 인스턴스이기 때문에 출력 결과는 'true'가 됩니다.
빌더 패턴
빌더 패턴은 객체가 어떤 식으로 구축되는지 모르는 상황에서 단계별로 객체를 생성하는 패턴입니다. 객체를 직접 생성하는 대신 빌더의 인스턴스를 만들고 빌더에서 객체를 대신 만들도록 합니다.
여러 생성자 매개변수가 필요한 경우에, 특히 변수의 타입이 동일하면 이 위치의 변수가 어떤 필드에 들어가는지 헷갈린 경험이 있으실지도 모르겠습니다.
그림 2-1의 상황처럼, 특히 같은 타입의 변수일 경우 객체를 초기화하는 일이 꽤나 혼란스럽습니다. 그 순서가 헷갈려 일일이 클래스 문서를 다시 보면서 찾는 경우가 허다합니다. (물론 IDE의 도움을 받으면 한결 편해집니다.)
이제 빌더 패턴을 사용하여 Person 클래스를 구현해 봅시다. 코드 길이 상 몇 개의 인스턴스 변수는 생략하였습니다.
이 패턴을 쓰면 객체를 초기화하는 과정이 훨씬 깔끔하고 이해하기 좋게 될 뿐 아니라, 매개변수를 추가하거나 제거하기도 편해집니다.
옵저버 패턴
옵저버 패턴을 사용하면 그 객체의 상태에 관심을 가지고 있는 옵저버에게 해당 객체의 상태가 바뀌었음을 알릴 수 있습니다.
우리가 흔히 알고 있는 모델-뷰-컨트롤러(MVC) 구조도 옵저버 패턴의 일종이라고 할 수 있습니다. 모델(데이터)이 변경되면 자동으로 뷰(인터페이스)가 새로 그려지기 때문입니다.
이제 옵저버 패턴을 구현한 자바 코드를 보겠습니다.
공부를 하려는 Duck과, 그런 Duck을 감시하는 Observer 클래스가 있습니다. Observer 생성자에 Duck 객체를 파라미터로 주입하고, 해당 Duck 객체가 공부를 시작하면 등록된 Observer(들)에게 그 사실을 알려줍니다. 실제로 해당 출력 결과는 "Current conditions: 3 hours"가 나옵니다.
마무리
디자인 패턴이 이렇게 유용하긴 하지만 모든 프로그래밍 문제에 대해 적용할 수 있는 만병통치약은 아닙니다. 디자인 패턴을 잘못 쓰면 코드가 복잡해질 수 있고, 패턴을 틀리게 구현했다가는 버그가 생기거나 성능이 나빠질 수도 있습니다. 그러나 C++나 자바 같은 객체지향 언어를 일상적으로 쓰는 개발자에게 디자인 패턴이 유용하다는 사실은 변함이 없는 것 같습니다.
참고
'Java & Spring Boot' 카테고리의 다른 글
@Getter 어노테이션을 이해해보자 (0) | 2023.08.07 |
---|---|
Java 예외에는 어떤 유형이 있을까? (0) | 2023.04.02 |
스프링 빈 중복 에러 해결하기 (0) | 2023.03.07 |
자원을 반납하자 (부제: try-catch-finally 멈춰!) (0) | 2023.02.26 |
당신이 Raw type을 지양해야 하는 이유 (0) | 2023.02.12 |