템플릿 메서드 패턴
- 상속을 통해 슈퍼클래스의 기능을 확장할 때 사용하는 패턴
- 변하지 않는 기능은 슈퍼클래스에서
- 자주 변경되며 확장할 기능은 서브클래스에서 => 템플릿 메서드가 좀 더 큰 범위의 패턴이다.
팩토리 메서드 패턴
- 상속을 통해 기능을 확장한다는 점에서 템플릿 메서드 패턴과 유사
- 서브클래스에서 구현할 메서드를 호출 후 필요한 타입의 객체를 반환한다는 점이 다름
- 서브클래스에서 다양한 방법으로 오브젝트를 생성하는 메서드 재정의 => 객체 생성 방법과 나머지 로직을 분리하는 것이 목적
개방 폐쇄 원칙 (OCP)
- 높은 응집도
- 하나의 모듈/클래스가 하나의 책임/관심사에만 집중되어 있는 것
- 변경이 일어날 때 해당 모듈에서 변하는 부분이 크다는 것
- 낮은 결합도
- 결합도 : 하나의 오브젝트가 변경이 일어날 때 관계를 맺는 다른 오브젝트에게 변화를 요구하는 정도
- 책임과 관심사가 다른 오브젝트끼리는 느슨하게 연결된 형태를 유지하는 것
- 결합도가 낮아지면 변화에 대응하는 속도가 높아지고, 구성이 깔끔, 확장성이 좋음
어플리케이션 컨텍스트와 설정정보
- 빈 팩토리 : 빈을 생성하고 관계를 설정하는 IoC의 기본 기능에 초점을 맞춘 것
- 어플리케이션 컨텍스트 : 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진
- 별도의 정보를 참고해서 빈의 생성, 관계설정 등 제어작업 총괄
- 장점
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다
- 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다
- 애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다
스프링 IoC 용어 정리
- 빈 Bean : 스프링이 IoC 방식으로 관리하는(관리되는) 오브젝트, 스프링이 직접 생성과 제어를 담당하는 오브젝트
- 빈 팩토리 Bean Factory : 스프링의 IoC를 담당하는 핵심 컨테이너, 빈 등록/생성/조회 등
- 애플리케이션 컨텍스트 Application Context : 빈 팩토리를 확장한 IoC 컨테이너
- 설정정보/설정 메타 정보 Configuration Metadata : 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보
- 컨테이너 Container : IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트, 빈 팩토리
프레임워크 vs 라이브러리
- 프레임워크 : 개발자의 코드를 사용
- 라이브러리 : 개발자가 사용
동일성과 동등성
- 동일성 : 두 개의 객체가 완전히 동일한 객체
==
- 동등성 : 두 개의 객체가 동일한 정보를 담고 있는 것
equals()
싱글톤 레지스트리
- 스프링이 직접 싱글톤 오브젝트를 만들고 관리하는 것
- 싱글톤 패턴 : 어떤 클래스를 어플리케이션 내에서 제한된 인스턴스 개수, 이름처럼 주로 하나만 존재하도록 강제하는 패턴
- 단일 오브젝트만 존재해야 하고, 이를 애플리케이션 여러 곳에서 공유하는 경우 주로 사용
- 클래스 밖에서 오브젝트를 생성하지 못하도록 생성자를
private
으로 만든다 - 생성된 싱글톤 오브젝트를 저장할 수 있는 자신과 같은 타입의 static 필드를 정의한다
- static 팩토리 메소드인
getInstance()
를 만들고 이 메소드가 최초로 호출되는 시점에서 한 번만 오브젝트가 만들어지게 한다. 생성된 오브젝트는 static 필드에 저장된다. - 한번 오브젝트가 만들어지고 난 후에는 getInstance() 메소드를 통해 이미 만들어져 스태틱 필드에 저장해둔 오브젝트를 넘겨준다
- 클래스 밖에서 오브젝트를 생성하지 못하도록 생성자를
- 주의할 점 : 무상태여야 한다
- private 생성자를 갖고 있기 때문에 상속할 수 없다 => 다형성 적용불가
- 테스트하기가 힘들다 (거의 불가능)
- 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다
- 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다
DI (의존성 주입)
- 런타임에 오브젝트끼리 의존관계가 만들어지는 것. (주입은 아니고 레퍼런스가 전달되는 것)
- A가 B에 의존한다면 A -> B
- A가 B에 의존한다 == A가 B를 사용한다 (B가 변하면 A에 영향을 미침)
느슨한 의존관계
- 인터페이스로 만들면 느슨한 의존관계를 만들 수 있다.
- 변화에 영향을 덜 받음, 결합도가 낮아짐 => 변경에서 자유로워진다.
의존관계 주입
- 구체적인 의존 오브젝트와 그것을 사용하는 클라이언트를 런타임에 연결하는 것
의존관계 검색 vs 주입
- 검색(DL) : 오브젝트 자기 자신이 빈일 필요없음
- 주입(DI) : 오브젝트 자기 자신이 반드시 빈 오브젝트여야 함
DI의 조건
- 클래스 모델, 코드에 의존관계가 드러나지 않아야 함 (인터페이스에 의존해야 함)
- 런타임 시 의존관계를 컨테이너나 팩토리가 결정해야 함
- 의존관계는 주입에 의해 만들어짐 (외부에서 의존 오브젝트를 제공)
런타임 의존관계
- 설계시에 의존관계를 가지고 있으면 서로 변경에 영향을 끼치는데
- 런타임에 가지게 하면 설계 시에는 의존성이 없어서 영향이 없음! => 런타임에 의존성을 가지게 되면 유연한 구조를 가지는 장점이 있음