디자인 패턴은 객체 지향의 특성 중
상속(extends), 인터페이스(interface/implements), 합성(객체를 속성으로 사용)을 이용한다.
01 어댑터 패턴(Adapter Pattern)
02 프록시 패턴(Proxy Pattern)
03 데코레이터 패턴(Decorator Pattern)
04 싱글턴 패턴(Singleton Pattern)
05 템플릿 메서드 패턴(Template Method Pattern)
06 팩토리 메서드 패턴(Factory Method Pattern)
07 전략 패턴(Strategy Pattern)
08 템플릿 콜백 패턴(Template Callback Pattern - 견본/회신 패턴)
09 그 외
예제 코드
스프링 프레임워크를 설명하는 공식적인 정의는 다음과 같다.
자바 엔터프라이즈 개발을 편하게 해주는 오픈소스 경량급 애플리케이션 프레임워크
자바 객체지향의 원리와 이해의 저자는 다음과 같이 정의했다.
OOP 프레임워크
스프링은 객체지향의 특성과 설계 원칙을 적용한 프레임워크이기 때문이다.
객체 자향과 설계 패턴의 주요 목적은 유지보수성 향상이다.
유지보수가 필요한 이유는 다음과 같다.
-
불충분한 요구사항 정의
-
기능 추가
-
설계 결함
-
기술 환경의 변화
어댑터 패턴
어댑터를 번역하면 변환기라고 할 수 있다. 변환기의 역할은 서로 다른 두 인터페이스 사이에 통신이 가능하게 하는 것이다,
자바 언어의 구조를 보면 플랫폼별 JRE에 대해 얘기가 나오는데 이를 어댑터 패턴이라고 할 수 있고, 어댑터 패턴은 개방 폐쇄 원칙을 활용한 설계 패턴이라고 할 수 있다.
JRE가 어댑터의 역할을 수행하고 있는 것이다.
어댑터 패턴은 합성, 즉 객체를 속성으로 만들어서 참조하는 디자인 패턴으로 한 문장으로 정리하면
→ 호출당하는 쪽의 메서드를 호출하는 쪽의 코드에 대응하도로 중간에 변환기를 통해 호출하는 패턴
문제 해결을 위해 어탭터 패턴을 사용한다면,
재사용 하려는 클래스와 공통 부모 클래스 사이에 adapter 클래스를 끼워넣는다.
클라이언트의 호출은 adapter 클래스가 받는다.
어떤 클래스에 대한 다른 사용법을 제공하기 위해 끼어들어가는 클래스를 wrapper class 라고 부른다.
재사용을 위해 가져온 클래스를 공통 인터페이스 규격에 맞추기 위해 중간에 wrapper를 끼워 넣는 구조가
adapter 패턴이다.
다형성으로 구현된 공통 인터페이스 구격에 맞추기 위한 목적의 구조가 아니라면
adapter 패턴이라고 부르지 않는다.
기존에 있는 시스템에 새로운 코드가 들어가거나 교체되어야 하는 경우 코드의 재사용성을 높이기 위한 방법이다.
다음은 어댑터 패턴의 구조이다.
- Client : 서드파티 라이브러리나 외부 시스템을 사용하려는 쪽
- Adaptee : 서드파티 라이브러리나 외부 시스템
- Target Interface : Adapter가 구현하는 인터페이스이다.
클라이언트는 Target Interface를 통해 Adaptee인 서드파티 라이브러리를 사용하게 된다. - Adapter : Client와 Adaptee 중간에서 호환성이 없는 둘을 연결시켜주는 역할이다.
클라이언트는 Target Interface를 통해 어댑터에 요청을 보낸다.
어댑터는 클라이언트의 요청을 Adapter가 이해할 수 있는 방법으로 전달하고 처리는 Adaptee가 한다.
클라이언트에서는 Target Interface 를 호출하는 것 처럼 보인다.
하지만 클라이언트의 요청을 전달받은 (Target Interface 를 구현한) Adapter 는 자신이 감싸고 있는 Adaptee 에게 실질적인 처리를 위임한다.
Adapter 가 Adaptee 를 감싸고 있는 것 때문에 Wrapper 패턴이라고도 불린다.
프록시 패턴
프록시는 대리자, 대변인이라는 뜻을 가진 단어다. 프록시 패턴의 경우 실제 서비스 객체가 가진 메서드왁 같은 이름의 메서드를 사용하는데, 이를 위해 인터페이스를 사용한다.
인터페이스를 사용하면 서비스 객체가 들어갈 자리에 대리자 객체를 대신 투입해 클라이너트 쪽에서는 실제 서비스 객체를 통해
메서드를 호출하고 반환값을 받는지, 대리자 객테를 통해 메서드를 호출하고 반환값을 받는지 전혀 모르게 처리할 수도 있다.
다음은 프록시 패턴을 사용한 클래스 다이어그램이다.
- Client는 프록시를 사용하여 원하는 서비스 메서드를 호출한다.
- Service는 실제 서비스를 구현하고 있다. (IService 인터페이스 구현)
- Proxy는 IService 인터페이스를 구현하고 (실제 서비스 참조 변수 사용) 실제 메서드를 호출한다.
다음은 프록시 패턴의 중요 포인트이다.
- 대리자는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
- 대리자는 실제 서비스에 대한 참조 변수를 갖는다. (합성)
- 대리자는 실제 서비스와 같은 이름을 가진 메서드를 호출하고 그 값을 클라이언트에게 돌려준다.
- 대리자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.
프록시 패턴은 실제 서비스 메서드의 반환 값에 가감하는 것을 목적으로 하지 않고 제어의 흐름을 변경하거나 다른 로직을 수행하기 위해 사용한다.
→ 프록시 패턴은 제어 흐름을 조정하기 위한 목적으로 중간에 대리자를 두는 패턴이고 개방 폐쇄 원칙과 의존 역전 원칙이 적용된 설계 패턴이다.
데코레이터 패턴
데코레이터 패턴은 프록시 패턴과 구현 방법이 같다. 다만 프록시 패턴은 클라이언트가 최종적으로 돌려 받는 반환값을 조작하지 않고 그대로 전달하는 반면
데코레이터 패턴은 클라이언트가 받는 반환값에 장식을 덧입힌다.
- 장식자는 실제 서비스와 같은 이름의 메서드를 구현한다. 이때 인터페이스를 사용한다.
- 장식자는 실제 서비스에 대한 참조 변수를 갖는다. (합성)
- 장식자는 실제 서비스와 같은 이름을 가진 메서드를 호출하고, 그 반환값에 장식을 더해 클라이언트에게 돌려준다.
- 장식자는 실제 서비스의 메서드 호출 전후에 별도의 로직을 수행할 수도 있다.
→ 메서드 호출의 반환값에 변화를 주기 위해 중간에 장식자를 두는 패턴
개방 폐쇄 원칙(OCP)과 의존 역전 원칙(DIP)이 적용된 설계 패턴임을 알 수 있다.
싱글턴 패턴
싱글턴 패턴이란 인스턴스를 하나만 만들어 사용하기 위한 패턴이다.
커넥션 풀, 스레드 풀, 디바이스 설정 객체 등과 같은 경우 인스턴스를 여러 개 만들게 되면 불필요한 자원을 사용하게 되고,
또 프로그램이 예상치 못한 결과를 낳을 수 있다. 싱글턴 패턴은 오직 인스턴스 하나만 만들고 그것을 계속해서 재사용 한다.
이를 구현하려면 객테 생성을 위한 new에 제약을 걸어야 하고, 만들어진 단일 객체를 반환할 수 있는 메서드가 필요하다.
따라서 다음 세 가지 요소가 반드시 필요하다.
- new를 실행할 수 없도록 생성자에 private 접근 제어자를 지정한다.
- 유일한 단일 객체를 반환할 수 있는 정적 메서드가 필요하다.
- 유일한 단일 객체를 참조할 정적 참조 변수가 필요하다.
단일 객체인 경우 결국 공유 객체로 사용되기 때문에 속성을 갖지 않게 하는 것이 정석이다. 다만 읽기 전용 속성을 갖는 것은 문제가 되지 않는다.
→ 클래스의 인스턴스, 즉 객체를 하나만 만들어 사용하는 패턴
템플릿 메서드 패턴
상위 클래스에 공통 로직을 수행하는 템플릿 메소드와 하위 클래스에 오버라이딩을 강제하는 추상 메서드 또는
선택적으로 오버라이딩할 수 있는 훅(Hook) 메서드를 두는 패턴을 템플릿 메서드 패턴이라고 한다.
→ 상위 클래스의 견본 메서드에서 하위 클래스가 오버라이딩한 메서드를 호출하는 패턴
예제 코드를 보면 의존 역전 원칙(DIP)을 활용하고 있음을 알 수 있다.
팩토리 메서드 패턴
팩토리 메서드는 객체를 생성 반환하는 메서드를 말한다.
여기에 패턴을 붙이면 하위 클래스에서 팩토리 메서드를 오버라이딩해서 객체를 반환하게 하는 것을 의미한다.
→ 오버라이드된 메서드가 객체를 반환하는 패턴
예제 코드를 보면 의존 역전 원칙(DIP)을 활용하고 있음을 알 수 있다.
전략 패턴
전략 패턴을 구성하는 세 요소는 꼭 기억해야 한다.
- 전략 메서드를 가진 전략 객체
- 전략 객체를 사용하는 컨텍스트(전략 객체의 사용자/소비자)
- 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트(제 3자, 전략 객체의 공급자)
상속을 이용하는 템플릿 메서드 패턴과 객체 주입을 통한 전략 메서드 패턴 중에서 선택/적용할 수 있다.
단일 상속만이 가능한 자바 언어에서는 상속이라는 제한이 있는 템플릿 메서드 패턴보다는 전략 패턴이 더 많이 활용된다.
→ 클라이언트가 전략을 생성해 전략을 실행할 컨텍스트에 주입하는 패턴
예제 코드를 보면 개발 폐쇄 원칙(OCP)과 의존 역전 원칙(DIP)이 적용된 것을 짐작할 수 있다.
템플릿 콜백 패턴
템플릿 콜백 패턴은 전략 패턴과 모든 것이 동일한데 전략을 익명 내부 클래스로 정의해서 사용한다는 특징이 있다.
→ 전략을 익명 내부 클래스로 구현한 전략 패턴
전략 패턴의 일종이므로 개발 폐쇄 원칙(OCP)과 의존 역전 원칙(DIP)이 적용된 설계 패턴이다.
그 외 다른 패턴들
스프링은 다양한 디자인 패턴을 활용하고 있다. 특히 스프링 MVC의 경우 프론트 컨트롤러 패턴과 MVC 패턴을 활용하고 있다.