home
자바
home
1️⃣

1장 오브젝트와 의존관계

1.1 초난감 DAO

DAO : DB를 사용해 데이터를 조회하거나 조작하는 기능을 전담하도록 만든 오브젝트
자바빈 : 두 가지 관례를 따라 만들어진 오브젝트
디폴트 생성자 : 자바빈은 파라미터가 없는 디폴트 생성자를 가지고 있어야 함. 툴이나 프레임워크에서 리플렉션을 이용해 오브젝트를 생성하기 때문
리플렉션 : 구체적인 클래스 타입을 알지 못해도, 그 클래스의 메소드, 타입, 변수들을 접근할 수 있도록 해주는 Java API
프로퍼티 : 자바빈이 노출하는 이름을 가진 속성. 프로퍼티는 set으로 시작하는 수정자 메소드(setter)와 get으로 시작하는 접근자 메소드(getter)를 이용해 수정 또는 조회 가능

1.2 DAO의 분리

1.2.1 관심사의 분리

개발자가 객체를 설계할 때 가장 염두에 둬야 할 사항, 미래의 변화를 어떻게 대비할 것인가 ⇒ 객체지향 프로그래밍의 발전 (실세계를 최대한 가깝게 모델링)
코드 변화의 폭을 최소한으로 줄여주기 (변경이 일어날 때 필요 작업 최소화, 문제를 일으키지 않도록 하기)
모든 변경과 발전은 한 번에 한 가지 관심사항에 집중되어 일어남 (but, 그에 따른 작업은 한 곳에 집중되지 않는다.)
관심사의 분리
관심이 같은 것끼리 하나의 객체 안으로, 관심이 다른 것은 서로 영향을 주지 않도록 분리하여 같은 관심에 효과적으로 집중하도록 만드는 것

1.2.2 커넥션 만들기의 추출

UserDao의 관심사항 세 가지

1.
DB와 연결을 위한 커넥션을 어떻게 가져올까
2.
사용자 등록을 위해 DB에 보낼 SQL 문장을 담을 Statement를 만들고 실행하는 것
3.
작업 후 Statement와 Connection 오브젝트 닫기

변경사항에 대한 검증: 리팩토링과 테스트

리팩토링
기존의 코드를 외부의 동작방식에는 변화 없이 내부 구조를 변경해서 재구성하는 작업 또는 기술
생산성 up, 코드 품질 up, 유지보수 용이, 견고하고 유연한 제품 개발 가능 !!
메소드 추출 기법 : 리팩토링에서 공통의 기능을 담당하는 메소드로 중복된 코드를 뽑아내는 것

1.2.3 DB 커넥션 만들기의 독립

문제 가정)
사용자가 다른 종류의 DB를 사용하고, DB커넥션을 가져오는 방법이 종종 변경될 가능성이 있으며, 소스코드를 사용자에게 직접 공개하고 싶지는 않을 때 어떻게 해야될까?!

상속을 통한 확장

관심사항을 분리해 상하위 클래스에 나눠 담기
데이터를 어떻게 등록하고 가져올 것인가 어떤 기능을 사용하는 지에 관심 ⇒ UserDao(슈퍼클래스)
DB 연결 방법은 어떻게 할 것인가 어떤 식으로 기능을 제공하는지에 관심 ⇒ NUserDao, DUserDao(서브클래스)
템플릿 메소드 패턴 : 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 메소드로 만든 뒤 서브클래스에서 이런 메소드를 필요에 맞게 구현해서 사용하는 방법
훅 메소드 : 슈퍼클래스에서 디폴트 기능을 정의해두거나 비워뒀다가 서브클래스에서 선택적으로 오버라이드 할 수 있도록 만들어둔 메소드
팩토리 메소드 패턴 : 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것 / 오브젝트 생성 방법을 슈퍼클래스의 기본 코드에서 독립시키는 방법
주로 인터페이스 타입으로 오브젝트를 리턴
서브클래스는 다양한 방법으로 오브젝트를 생성하는 메소드를 재정의 가능
팩토리 메소드 : 서브클래스에서 오브젝트 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메소드
디자인 패턴
소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션
객체지향적인 설계로 문제 해결에 적용할 수 있는 확장성 추구 방법은 클래스 상속, 오브젝트 합성
패턴을 적용할 상황, 해결해야 할 문제, 솔루션의 구조와 각 요소의 역할과 핵심 의도가 무엇인지 기억해 두기
상속의 한계점
이미 다른 목적을 위해 상속하고 있을 시 다중상속 불가
상속을 통한 상하위 클래스의 관계는 too much 밀접함
상속 코드가 사용된 클래스들이 계속 만들어진다면 상속을 통해 만들어진 코드가 매 클래스마다 중복돼서 나타나는 문제가 발생함

1.3 DAO의 확장

1.3.1 클래스의 분리

완전히 독립적인 클래스로 분리
UserDao의 코드가 SimpleConnectionMaker라는 특정 클래스에 종속되어 있기 때문에 상속을 사용했을 때 처럼 UserDao 코드의 수정 없이 DB 커넥션 생성 기능을 변경할 방법이 없다.
문제점
1.
SimpleConnectionMaker의 메소드
다른 클래스의 메소드명이 다르다면 커넥션을 가져오는 코드를 일일이 변경해야 하는 문제
2.
DB 커넥션을 제공하는 클래스가 어떤 것인지 UserDao가 구체적으로 알고 있어야 한다는 점
UserDao에 SimpleConnectionMaker라는 클래스 타입의 인스턴스 변수까지 정의해놓아서, 다른 클래스를 구현하면 UserDao 자체를 수정해야 함
⇒ UserDao가 바뀔 수 있는 정보, 즉 DB 커넥션을 가져오는 클래스에 대해 너무 많이 알고 있기 때문 (그 클래스에서 커넥션을 가져오는 메소드는 이름이 뭔지까지 일일이 알고 있어야 한다.)
=⇒ 종속적!!!

1.3.2 인터페이스의 도입

추상화 : 공통적인 성격을 뽑아내어 따로 분리해내는 작업 ⇒ 인터페이스
자신을 구현한 클래스에 대한 구체적인 정보는 모두 감추기 때문에 접근하는 쪽에서 오브젝트를 만들 때 사용할 클래스를 몰라도 됨
기능만 정의, 구현방법은 나타나 있지 않음

1.3.3 관계설정 책임의 분리*

UserDao와 / UserDao가 사용할 ConnectionMaker의 특정 구현 클래스 사이의 관계를 설정해주는 것에 관한 관심 (=DConnectionMaker, NConnectionMaker)
사용되는 오브젝트 ⇒ 서비스 / 사용하는 오브젝트 ⇒ 클라이언트
클라이언트 오브젝트에 기능 분리
오브젝트와 오브젝트 사이의 관계를 설정해줘야 함 - ??????????
직접 생성자를 호출해서 직접 오브젝트를 만드는 방법
외부에서 만들어준 것을 가져오는 방법
package main.springbook.user.dao; import java.sql.SQLException; /** * 1.3.3 관계설정 책임의 분리 * - 관계설정 책임이 추가된 메소드 * - 클라이언트 코드 * - UserDao의 변경 없이 다른 사용자가 자유로운 DB 접속 클래스를 만들어 사용 가능 */ public class UserDaoTest { public static void main(String[] args) throws ClassNotFoundException, SQLException{ // UserDao가 사용할 ConnectionMaker 구현 클래스를 결정하고 오브젝트 만들기 ConnectionMaker connectionMaker = new DConnectionMaker(); // 1. UserDao 생성 // 2. 사용할 ConnectionMaker 타입의 오브젝트 제공, 결국 두 오브젝트 사이의 의존관계 설정 효과 // *UserDao 클래스에서 생성자 수정함 public UserDao(ConnectionMaker connectionMaker){ - } UserDao dao = new UserDao(connectionMaker); } }
Java
복사
상속을 사용해 분리했을 때보다 훨씬 유연함
ConnectionMaker라는 인터페이스를 사용하기만 하면 다른 DAO클래스에도 ConnectionMaker의 구현 클래스들을 적용 가능
DAO가 많아져도 DB 접속 방법에 대한 관심은 오직 한 군데에 집중됨 !!!
서로 영향을 주지 않고 필요에 따라 자유롭게 확장 가능

1.3.4 원칙과 패턴

초난감 DAO 코드의 개선 결과를 객체지향 기술의 이론을 통해 설명

개방 폐쇄 원칙

'클래스나 모듈은 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다'
[그림 1-7] 인터페이스를 통해 제공되는 확장 포인트는 개방, 인터페이스를 이용하는 클래스는 불필요한 변화가 일어나지 않도록 폐쇄되어있음
디자인 패턴 ⇒ 특별한 상황에서 발생하는 문제에 대한 좀 더 구체적인 솔루션 객체지향 설계 원칙 ⇒ 좀 더 일반적인 상황에서 적용 가능한 설계 기준
SOLID 5가지 객체지향 설계 원칙 - SRP(The Single Responsibility Principle) : 단일 책임 원칙 - OCP(The Open Closed Principle) : 개방 폐쇄 원칙 - LSP(The Liskov Substitution Principle) : 리스코프 치환 원칙 - ISP(The Interface Segregation Principle) : 인터페이스 분리 원칙 - DIP(The Dependency Inversion Principle) : 의존관계 역전 원칙

높은 응집도와 낮은 결합도

높은 응집도 : 하나의 모듈, 클래스가 하나의 책임 또는 관심사에만 집중되어 있음
낮은 결합도 : 책임과 관심사가 다른 오브젝트 또는 모듈과 느슨하게 연결된 형태를 유지하는 것 / 하나의 오브젝트가 변경이 일어날 때에 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도
서로 독립적이며 알 필요도 없음
변화에 대응하는 속도가 높아짐
구성이 깔끔해짐
확장이 편리함

전략패턴

자신의 기능 맥락에서, 필요에 따라 변경이 필요한 알고리즘을 인터페이스를 통해 통째로 외부로 분리시키고, 이를 구현한 구체적인 알고리즘 클래스를 필요에 따라 바꿔서 사용할 수 있게 하는 디자인 패턴 *알고리즘 : 독립적인 책임으로 분리가 가능한 기능

1.4 제어의 역전(IoC Inversuin of Control)

1.4.1 오브젝트 팩토리

클라이언트 UserDaoTest
성격이 다른 책임이나 관심사는 분리 !!

팩토리

1.
분리시킬 기능을 담당할 클래스를 하나 만든다.
2.
이 클래스의 역할은 객체의 생성 방법을 결정하고 그렇게 만들어진 오브젝트를 돌려주는 것인데, 이런 일을 하는 오브젝트를 팩토리라고 부른다.

설계도로서의 팩토리

UserDao, ConnectionMaker
각각 애플리케이션의 핵심적인 데이터 로직과 기술 로직 담당
실질적인 로직을 담당하는 컴포넌트
DaoFactory
이러한 애플리케이션의 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있음
애플리케이션을 구성하는 컴포넌트의 구조와 관계를 정의한 설계도 같은 역할(어떤 오브젝트 → 어떤 오브젝트를 사용?! 하는지를 정의해놓은 코드)

1.4.2 오브젝트 팩토리의 활용

DaoFactory에 UserDao가 아닌 다른 DAO의 생성 기능을 넣으면 어떻게 될까? ⇒ ConnectionMaker 구현 클래스의 오브젝트를 생성하는 코드가 메소드마다 반복되는 문제 ⇒ 분리
public class DaoFactory{ public UserDao userDao(){ return new UserDao(new DConnectionMaker()); } public AccountDao accountDao(){ return new AccountDao(new DConnectionMaker()); } public MessageDao messageDao(){ return new MessageDao(new DConnectionMaker()); } // new DConnectionMaker() => ConnectionMaker 구현 클래스를 선정하고 생성하는 코드의 중복 !! }
Java
복사
분리 전
public class DaoFactory{ public UserDao userDao(){ return new UserDao(connectionMaker()); } public AccountDao accountDao(){ return new AccountDao(connectionMaker()); } public MessageDao messageDao(){ return new MessageDao(connectionMaker()); } public ConnectionMaker connectionMaker(){ return new DConnectionMaker(); // 분리해서 중복을 제거한 ConnectionMaker 타입 오브젝트 생성 코드 // 구현 클래스를 변경하고 싶을 때도 여기만 수정하면 됨 } }
Java
복사
분리 후

1.4.3 제어권의 이전을 통한 제어관계 역전

제어의 역전이란?
프로그램의 제어 흐름 구조가 뒤바뀌는 것
모든 제어 권한(결정, 생성)을 다른 대상에게 위임함
예시
1.
서블릿 : 서블릿에 대한 제어 권한을 가진 컨테이너가 적절한 시점에 클래스 오브젝트를 만들고 그 안의 메소드를 호출
2.
템플릿 메소드 패턴 : 제어권을 상위 템플릿 메소드에 넘기고 자신은 필요할 때 호출되어 사용되도록 함
3.
프레임워크 : 애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작
4.
책에서 DaoFactory를 도입했던 과정 (ConnectionMaker의 구현 클래스를 결정하고 오브젝트를 만드는 제어권을 넘김)

1.5 스프링의 IoC

스프링의 핵심
⇒ 빈 팩토리 / 애플리케이션 컨텍스트

1.5.1 오브젝트 팩토리를 이용한 스프링 IoC

애플리케이션 컨텍스트와 설정정보

빈 bean
스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트
빈 팩토리 bean factory
빈의 생성과 관계설정 같은 제어를 담당하는 IoC 오브젝트
애플리케이션 컨텍스트 application context
빈 팩토리와 동일하지만 좀 더 확장된 개념
빈 팩토리와 용어가 함께 쓰일 때는
빈 팩토리는 → IoC의 기본기능에 초점
애플리케이션 컨텍스트는 → 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 좀 더 부각
설계도
⇒ 애플리케이션 컨텍스트와 그 설정 정보
IoC방식을 이용해 애플리케이션 컴포넌트를 생성하고, 사용할 관계를 맺어주는 등의 책임을 담당

1.5.2 애플리케이션 컨텍스트의 동작방식

오브젝트 팩토리 (DaoFactory)
DAO 오브젝트를 생성하고 DB 생성 오브젝트와 관계를 맺어주는 제한적인 역할
애플리케이션 컨텍스트
스프링의 가장 대표적인 오브젝트
애플리케이션에서 IoC를 적용해서 관리할 모든 오브젝트에 대한 생성과 관계설정을 담당
생성, 연관관계 정보를 별도의 설정정보를 통해 얻음
1.
DaoFactory 클래스를 설정정보로 등록
2.
@Bean이 붙은 메소드의 이름을 가져와 빈 목록을 만듦
3.
getBean() 메소드 호출 → 자신의 빈 목록에서 요청한 이름이 찾음.
4.
있다면 빈을 생성하는 메소드를 호출해서 오브젝트를 생성시킨 후 클라이언트에 돌려줌
오브젝트 팩토리로 직접 사용 했을 때와 비교하여 애플리케이션 컨텍스트를 사용했을 때 장점
클라이언트는 구체적인 팩토리 클래스를 알 필요 없다
애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다
애플리케이션 컨텍스트는 빈을 검색하는 다양한 방법을 제공한다
getBean() 메소드는 빈의 이름을 이용해 빈을 찾아준다. 타입만으로 빈을 검색하거나 특별한 애노테이션 설정이 되어 있는 빈을 찾을 수도 있다.

1.5.3 스프링 IoC의 용어 정리

빈 bean
스프링이 IoC 방식으로 관리하는, 관리되는 오브젝트
애플리케이션에서 만들어지는 모든 오브젝트 중에 스프링이 직접 그 생성과 제어를 담당하는 오브젝트만을 빈이라고 부름
빈 팩토리 bean factory
스프링의 IoC를 담당하는 핵심 컨테이너
빈을 등록, 생성, 조회, 반납, 그 외 부가적인 빈을 관리하는 기능을 담당
애플리케이션 컨텍스트 application context
빈 팩토리를 확장한 IoC 컨테이너
빈을 등록, 관리하고 + 스프링이 제공하는 각종 부가 서비스를 추가로 제공
ApplicationContext → 애플리케이션 컨텍스트가 구현해야 하는 기본 인터페이스를 가리킴
ApplicationContext는 BeanFactory를 상속
설정정보/ 설정 메타정보
애플리케이션 컨텍스트 또는 빈 팩토리가 IoC를 적용하기 위해 사용하는 메타정보
'configuration' 구성정보, 형상정보
컨테이너 또는 IoC 컨테이너
IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트나 빈 팩토리를 컨테이너 또는 IoC 컨테이너라고 한다.
컨테이너라는 말 자체가 IoC의 개념을 담고 있기 때문에 스프링 컨테이너라고 부른다.
그냥 '스프링'이라고 부르기도 한다.
스프링 프레임워크
IoC 컨테이너, 애플리케이션 컨텍스트를 포함해서 스프링이 제공하는 모든 기능을 통틀어 말할 때 주로 사용

1.6 싱글톤 레지스트리와 오브젝트 스코프

오브젝트의 동일성과 동등성
동일한 오브젝트
동일성 비교(identity)
== 연산자
두 개의 오브젝트가 동일하다면, 사실은 하나의 오브젝트만 존재하고 두 개의 오브젝트 레퍼런스 변수를 가짐
동일한 정보를 담고 있는 오브젝트
동등성 비교(equality)
equals() 메소드
메모리상에 각기 다른 오브젝트가 존재
DaoFactory의 userDao()를 여러 번 호출했을 때 ⇒ 직접 만든 오브젝트 팩토리와 스프링의 애플리케이션 컨텍스트의 동작방식 차이 !!
DaoFactory factory = new DaoFactory(); UserDao dao1 = factory.userDao(); UserDao dao2 = factory.userDao(); System.out.println(dao1); System.out.println(dao2); // => 각기 다른 값을 가진 오브젝트임을 알 수 있다. // => userDao를 호출할 때 마다 새로운 오브젝트 생성
Java
복사
직접 생성한 DaoFactory 오브젝트 출력 코드
ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class); UserDao dao3 = context.getBean("userDao", UserDao.class); UserDao dao4 = context.getBean("userDao", UserDao.class); System.out.println(dao3); System.out.println(dao4); System.out.println(dao3 == dao4); // true // 두 오브젝트의 출력 값이 같다. // => 하나의 오브젝트!
Java
복사
스프링 컨텍스트로부터 가져온 오브젝트 출력 코드

1.6.1 싱글톤 레지스트리로서의 애플리케이션 컨텍스트

애플리케이션 컨텍스트는
우리가 만들었던 오브젝트 팩토리DaoFactory와 비슷한 방식으로 동작하는 IoC 컨테이너
동시에 싱글톤을 저장하고 관리하는 싱글톤 레지스트리이기도 함
스프링은 기본적으로 내부에서 생성하는 빈 오브젝트를 모두 싱글톤으로 만든다.
디자인 패턴의 싱글톤 패턴과 비슷한 개념이지만 구현 방법은 다르다.
*싱글톤이란?

서버 애플리케이션과 싱글톤

왜 스프링은 싱글톤으로 빈을 만들까?
스프링이 주로 적용되는 대상이 자바 엔터프라이즈 기술을 사용하는 서버환경이기 때문
서버 과부하 문제 때문에 일찍이 서비스 오브젝트라는 개념을 사용
⇒ 서블릿 : 클래스당 하나의 오브젝트만 만들어두고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용
싱글톤 패턴
애플리케이션 안에 제한된 수, 대개 한 개의 오브젝트만 만들어서 사용하는 것
서버환경에서 사용 권장
but, 문제점이 많은 패턴임 ! ⇒ 안티패턴 이라고 불리기도 함

싱글톤 패턴의 한계

자바에서 싱글톤을 구현하는 방법
private 생성자를 갖고 있기 때문에 상속할 수 없다
오직 싱글톤 클래스 자신만이 자기 오브젝트를 만들도록 제한하는 것
객체지향의 장점인 상속과 이를 이용한 다형성을 적용할 수 없음
싱글톤은 테스트하기 힘들다
서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못함
싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못함
싱글톤의 스태틱 메소드를 이용해 언제든지 싱글톤에 쉽게 접근할 수 있기 때문에 애플리케이션 어디서든지 사용될 수 있고, 그러다 보면 자연스럽게 아무 객체나 자유롭게 접근하고 수정하고 공유할 수 있는 전역 상태로 사용되기 쉽다

싱글톤 레지스트리

싱글톤 패턴의 구현 방식은 여러 가지 단점이 있기 때문에, 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공한다. ⇒ 싱글톤 레지스트리
스태틱 메소드와 private 생성자를 사용해야 하는 비정상적인 클래스가 아니라 평범한 자바 클래스를 싱글톤으로 활용하게 해준다는 장점
평범한 자바 클래스도 IoC 컨테이너를 사용해서 생성과 관계설정, 사용 등에 대한 제어권을 컨테이너에 넘기면 손쉽게 싱글톤 방식으로 만들어짐
public 생성자를 가질 수 있음
테스트도 가능함
생성자 파라미터를 이용해서 사용할 오브젝트를 넣을 수도 있음

1.6.2 싱글톤과 오브젝트의 상태

싱글톤은 멀티스레드 환경이라면 여러 스레드가 동시에 접근하여 사용할 수 있기 때문에 상태 관리에 주의해야 함
무상태 방식 으로 만들어져야 한다.
상태정보를 내부에 갖고 있지 않은 상태
다중 사용자의 요청을 한꺼번에 처리하는 스레드들이 동시에 싱글톤 오브젝트의 인스턴스를 수정하는 것은 매우 위험하다. 저장할 공간이 하나뿐이라서 서로 값을 덮어쓰고 자신이 저장하지 않은 값을 읽어올 수 있기 때문이다. (데이터가 엉망이 될 수 있다)
상태유지 방식
개별적으로 바뀌는 정보는 인스턴스 변수가 아닌 로컬 변수로 정의하거나, 파라미터로 주고받으면서 사용하게 해야 한다.
읽기 전용의 정보는 인스턴스 변수를 사용해도 상관없다.

1.6.3 스프링 빈의 스코프

스코프 : 스프링이 관리하는 오브젝트, 즉 빈이 생성되고, 존재하고, 적용되는 범위
싱글톤 스코프
프로토타입 스코프
싱글톤과 달리 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어줌
요청 스코프
세션 스코프

1.7 의존관계 주입(DI)

1.7.1 제어의 역전(IoC)과 의존관계 주입

의존관계 주입 Dependency Injection
스프링 IoC 기능의 대표적인 동작원리

1.7.2 런타임 의존관계 설정

의존관계

두 개의 클래스 또는 모듈이 의존관계에 있다고 말할 때는 항상 방향성을 부여해줘야 한다. (누가 누구에게 의존하는 관계에 있다는 식)
A가 B에 의존하고 있음
'의존하고 있다' 의 의미
의존대상(B)가 변하면 그것이 A에 영향을 미친다는 뜻
B의 기능이 추가, 변경 혹은 형식이 바뀌면 A에게 영향을 미침
'사용에 대한 의존관계'
A가 B를 사용하는 경우, 예를 들어 A에서 B에 정의된 메소드를 호출해서 사용하는 경우
의존관계의 방향성
A가 B에 의존하고 있지만 B는 A에 의존하지 않는다.
즉, B는 A의 변화에 영향을 받지 않는다.

UserDao의 의존관계

UserDao가 ConnectionMaker에 의존하고 있는 형태
즉, ConnectionMaker 인터페이스 변한다면 UserDao가 영향을 받게 된다.
하지만 DConnectionMaker 등이 다른 것으로 바뀌거나 그 내부에서 사용하는 메소드에 변화가 생겨도 UserDao에 영향을 주지 않는다.
⇒ 인터페이스에 대해서만 의존관계를 만들어둠으로서, 결합도가 낮아진다.

1.7.3 의존관계 검색과 주입

1.7.5 메소드를 이용한 의존관계 주입

일반 메소드를 이용해 의존 오브젝트와의 관계 주입하기
수정자(setter) 메소드를 이용한 주입
외부에서 오브젝트 내부의 애트리뷰트 값을 변경하려는 용도
메소드는 항상 set으로 시작
파라미터로 전달된 값을 보통 내부의 인스턴스 변수에 저장하는 것
일반 메소드를 이용한 주입
수정자 메소드와는 달리 한 번에 여러 개의 파라미터를 받을 수 있음
자바 코드 보다 XML을 사용하는 경우에 자바빈 규약을 따르는 수정자 메소드가 사용하기 편리함

1.8 XML을 이용한 설정

자바 클래스 외의 방법으로 DI 의존관계 설정정보를 만들 수 있는 대표적인 방법 → XML
XML은 단순 텍스트 파일 → 다루기 쉽다.
컴파일 같은 별도의 빌드 작업이 없다.
스키마나 DTD를 이용해서 정해진 포맷을 따라 작성됐는지 쉽게 확인 가능

1.9 정리

책임이 다른 코드를 분리해서 두 개의 클래스로 만들었다. (관심사의 분리, 리팩토링)
그 중 바뀔 수 있는 쪽의 클래스는 인터페이스를 구현하도록 하고, 다른 클래스에서 인터페이스를 통해서만 접근하도록 만들었다. ⇒ 인터페이스를 정의한 쪽의 구현 방법이 달라져 클래스가 바뀌더라도, 그 기능을 사용하는 클래스의 코드는 같이 수정할 필요가 없다. (전략 패턴)
이를 통해 불필요한 변화가 발생하지 않도록 막아주고, 자신이 사용하는 외부 오부젝트의 기능은 자유롭게 확장하거나 변경할 수 있게 만들었다. (개방 폐쇄 원칙)
==⇒ 낮은 결합도와 높은 응집도를 가진 깔끔한 코드를 만들었다.
오브젝트가 생성되고 여타 오브젝트와 관계를 맺는 작업의 제어권을 별도의 오브젝트 팩토리를 만들어 넘김 / 오브젝트 팩토리의 기능을 일반화한 IoC 컨테이너로 넘겨서 오브젝트가 자신이 사용할 대상의 생성이나 선택에 관한 책임으로부터 자유롭게 만들어줬다. (제어의 역전/IoC)
전통적인 싱글톤 패턴 구현 방식의 단점을 살펴보고, 서버에서 사용되는 서비스 오브젝트로서의 장점을 살릴 수 있는 싱글톤을 사용하면서도 싱글톤 패턴의 단점을 극복하도록 설계된 컨테이너를 활용하는 방법에 대해 알아봤다. (싱글톤 레지스토리)
설계 시점과 코드에는 클래스와 인터페이스 사이의 느슨한 의존관계만 만들어 놓고, 런타임 시에 실제 사용할 구체적인 의존 오브젝트를 제 3자(DI 컨테이너)의 도움으로 주입받아서 다이내믹한 의존관계를 갖게 해주는 IoC의 특별한 케이스를 알아봤다. (의존관계 주입/DI)
의존 오브젝트를 주입할 때 생성자를 이용하는 방법과 수정자 메소드를 이용하는 방법을 알아봤다. (생성자 주입과 수정자 주입)
XML을 이용해 DI 설정정보를 만들고 의존 오브젝트가 아닌 일반 값을 외부에서 설정해서 런타임 시에 주입하는 방법을 알아봤다. (XML 설정)