purplely88's home

시작에 앞서

6장을 완료해주세요.

DI 

오래 기다리셨습니다.

5장과 6장에서 의존성과 주입에 대해 알아보았습니다만, DI는 이 두 가지를 동시에 한다고 생각하시면 될 거 같습니다.

 

DI 내부 처리

일단 DI 내부 처리가 어떻게 일어나는지 한번 알아보겠습니다.

 

1. DI의 관리 대상 클래스를 찾는다. (컨포넌트 스캔)

알아보실 수 있으시겠죠..?

스프링을 기동 하면, 컨포넌트 스캔이라고 불리는 처리가 이루어집니다.

이것은 DI에서 관리하는 대상의 어노테이션이 붙은 클래스를 찾는 처리입니다.

 

컨포넌트 스캔 대상의 어노테이션은 다음과 같습니다.

@Component

@Controller

@Service

@Repository

@Configuration

@RestController

@ControllerAdvice

@ManagedBean

@Named

 

위에 어노테이션이 붙은 클래스가 DI의 대상이 됩니다.

또한 어노테이션이 붙은 클래스를 빈(Bean)이라고 합니다.

 

빈 (Bean)

물론, 어노테이션을 붙이지 않아도 DI 컨테이너에 클래스를 등록하는 것도 가능합니다

이로 인해, 정확히는 DI 컨테이너상에서 관리하는 클래스를 빈(Bean)이라고 합니다.

 

2. 인스턴스 생성과 주입

다음으로는 DI 컨테이너에 등록된 Bean의 인스턴스 생성과 주입을 한다고 생각하시면 됩니다.

어디까지나 간단한 입니다. 실제로는 다르니 이해로써만 참고해주세요.

DI 대상 클래스 (Bean)을 모은 후에는, 그것들의 인스턴스를 DI가 생성합니다.

그리고 생성한 인스턴스를 @Autowired 어노테이션이 붙은 필드 곳곳에 주입합니다.

 

위 이미지의 DI 컨테이너를 보시면, 안에 각 클래스의 인스턴스를 생성해 두고, 그 인스턴스를 getter로 취득하는 이미지입니다. 그리고 @Autowired가 붙어있는 필드들에는 DI 컨테이너의 getter를 호출하는 이미지입니다.

 

이것은 6장에서 만든 Factory 클래스와 상당히 비슷합니다.

하지만 Factory 클래스와 달리 매회 new 처리는 하지 않습니다만, 매회 new 처리하게 할 수도 있습니다.

 

즉, @Component 등의 어노테이션을 붙이는 것만으로도 하나하나 Factory 클래스를 만들 필요가 없다는 이야기가 됩니다.

 

@Autowired를 쓰는 곳

@Autowired를 쓰는 곳은 아래의 3곳입니다.

1. 필드 변수

2. 생성자 파라미터

3. setter 파라미터

이 외에는 @Autowired를 붙일 수 없습니다. 예를 들어 메서드 내부 로컬 변수에는 붙일 수 없습니다.

 

@Autowired를 쓰는 곳(2. 생성자 파라미터)

생성자 앞에 @Autowired를 붙임으로써, 파라미터에 인스턴스가 반환됩니다.

@Autowired

public class TestClass(xxxComponent component) {

  super();

  this.component = component;

}

 

@Autowired를 쓰는 곳(3. setter 파라미터)

setter 앞에 @Autowired를 붙임으로써, 파라미터에 인스턴스가 반환됩니다.

@Autowired

public class void setxxxComponent(xxxComponent component) {

  this.component = component;

}

 

이와 같이 클래스의 인스턴스를 생성하여 주입하는 것이 DI 컨테이너의 기능입니다.

 

DI 코딩 방법

 

DI를 코딩하는 방법은 총 5가지가 있습니다.

1. 어노테이션 베이스

2. JavaConfig

3. xml

4. JavaConfig + 어노테이션

5. xml + 어노테이션

 

지금까지 보여드린 방식은 1. 어노테이션 베이스입니다.

즉, @Controller, @Service만 사용한 코딩 방법입니다.

 

이번 코딩 방식에는 2번과 4번에 대해서 설명드리겠습니다.

 

JavaConfig

1. DI의 관리대상 클래스를 찾는다. (컨포넌트 스캔)

처음으로 DI 컨테이너에 등록하는 Bean을 정의합니다.

 

@Bean을 붙인 getter의 반환 값이 DI 컨테이너에 Bean으로 등록됩니다.

먼저 @Configuration 어노테이션을 붙인 클래스를 준비합니다.

그 클래스 안에는 @Bean 어노테이션이 붙은 getter 메서드를 준비하면, getter 반환 값이 Bean으로써 DI 컨테이너에 등록됩니다.

 

2. 인스턴스 생성과 주입

다음으로는 DI 컨테이너에 등록한 Bean의 인스턴스 생성과 주입을 한다고 생각하시면 됩니다.

이전 이미지를 그대로 가져왔습니다만, 꼭 집어서 추가될 부분은 DI 컨테이너 안에 private JavaConfig config = new JavaConfig(); 가 있겠네요.

DI 컨테이너 안에 JavaConfig 클래스와 Bean 인스턴스를 준비한 후, 각 인스턴스를 getter로 취득하는 이미지입니다.

그리고 @Autowired가 붙은 부분에 getter로 호출하는 이미지입니다.

이건 DI 코딩 방법 1. 어노테이션 베이스와 같습니다.

 

1. 어노테이션 베이스에서는 @Component 혹은 @Controller가 붙은 클래스를 스프링에서 자동으로 DI 컨테이너에 등록해줍니다. 한편, 2. JavaConfig에서는 @Bean 어노테이션이 붙은 getter의 반환 값을 DI 컨테이너에서 관리해줍니다.

즉, 2. JavaConfig에서는 DI 컨테이너에서 관리하는 인스턴스 분(개수)의 메서드를 준비하지 않으면 안 됩니다.

 

그럼 JavaConfig 방식은 굳이 안 써도 되지 않나?라고 생각하실 수 있습니다만, JavaConfig 방식은 상세한 설정이나 교체가 가능합니다. 예를 들어, 인스턴스를 생성할 때에 생성자에 전달하는 값을 설정할 수 있습니다.

혹은 JavaConfig 클래스 교체하여 개발환경용/본 환경용과 같이 교체하면서 사용이 가능합니다.

 

그래도 역시 개발규모가 크면 클수록 JavaConfig 안에 정의해야만 하는 메서드가 늘어갑니다.

이것을 회피하기 위해 통상은 1. 어노테이션 베이스 방식과 2. JavaConfig 방식을 같이 사용합니다. 

이 두 가지 방식을 사용하는 것이 4. JavaConfig + 어노테이션 방식입니다.

 

4. JavaConfig + 어노테이션

이 방식은 DI에서 관리하고 싶은 클래스에 @Controller와 같은 어노테이션을 붙이고, 상세한 설정을 하고 싶은 인스턴스만 JavaConfig에 설정하는 방식입니다.

보통 소규모 애플리케이션이라고 하면 1. 어노테이션 베이스 방식으로 개발합니다. 그리고 규모가 크거나 설정 교체와 같은 작업을 하고 싶을 때에는 4. JavaConfig + 어노테이션 방식으로 개발합니다.

 

추후에 4. JavaConfig + 어노테이션 방식으로 Bean정의로 코딩하는 것을 보여드리겠습니다.

 

엥!? xml 방식은...?

xml 은 JavaConfig에서 설정하는 내용을 단지 xml로 옮긴 거뿐입니다.

 

 

다음 포스트에서는 DI 라이프 사이클에 대해서 알아보겠습니다.

'프로그래밍 > 스프링 부트' 카테고리의 다른 글

9. 데이터 바인딩 & 밸리데이션 (1/4)  (0) 2020.06.20
8. DI (4/4)  (0) 2020.06.18
6. DI (2/4)  (0) 2020.06.16
5. DI (1/4)  (0) 2020.06.14
4. 웹 애플리케이션 작성 (데이터 베이스로부터 값 취득)  (0) 2020.06.14

시작에 앞서

5장을 완료해주세요.

 

주입

의존성 다음에는 주입에 대해서 이해를 해보도록 하겠습니다.

계속해서 5장의 자동차를 예를 들어, 이번에는 자동차를 대량 생산해보겠습니다.

 

대량생산에 맞춘 코드는 다음과 같습니다.

 

메인 클래스 (기본 생략)

 

// 엔진 생성

Engine hyundaiEngine1 = new HyundaiEngine();

Engine hyundaiEngine2 = new HyundaiEngine();

Engine kiaEngine1 = new KiaEngine();

 

// 자동차 생산

Car car1 = new Car(hyundaiEngine1);

Car car1 = new Car(hyundaiEngine2);

Car car1 = new Car(kiaEngine1);

 

여기서는 하나하나 생성한 인스턴스를 Engine인터페이스형의 변수에 넣고 있습니다.

이와 같이 인터페이스형 변수에 인스턴스를 넣는 것을 주입이라고 합니다.

 

이것으로 주입 설명은 끝...이라고 보이시겠지만, 실제로는 조금 문제가 있어 보입니다.

예를 들어 현대가 새로운 엔진을 만들고 거기에 맞춰 자동차를 생산하다고 생각해봅시다.

그러면 현대의 새로운 엔진 클래스를 준비하고, 메인 클래스를 수정해야 할 필요가 있습니다.

 

엔진 클래스 (현대 버전2)

public class HyundaiEngineVer2 extends HyundaiEngine {

 

  // 생성자

  public HyundaiEngineVer2() {

    super();

  }

 

  // 기동 메서드

  @Override

  public void boot() {

    System.out.println("현대 엔진 기동 (버전 2)");

 

  // 정지 메서드

  @Override

  public void stop() {

    System.out.println("현대 엔진 정지 (버전 2)");

  }

}

 

버전 2 클래스는 버전1 클래스를 상속합니다.

 

메인 클래스 (기본 생략)

 

// 엔진 생성

Engine hyundaiEngine1 = new HyundaiEngineVer2();

Engine hyundaiEngine2 = new HyundaiEngineVer2();

Engine kiaEngine1 = new KiaEngine();

 

// 자동차 생산

Car car1 = new Car(hyundaiEngine1);

Car car1 = new Car(hyundaiEngine2);

Car car1 = new Car(kiaEngine1);

 

엔진을 생성하는 부분에 버전2 엔진 클래스로 변경한 게 보이실 겁니다.

지금 하고 있는 건 새로운 엔진 클래스를 추가하는 처리와 같습니다.

하지만 엔진 생성하는 코드가 늘면 늘 수록 자칫하면 코드 수정이 대량으로 많아지는 의미로 볼 수 있습니다.

 

이 문제는 간단하게 해결할 수 있습니다. 그건 바로 Factory 클래스를 만드는 것입니다. 오호!

Factory 클래스란 인스턴스를 생산하는 클래스를 뜻합니다. 이건 자바에서 자주 사용되는 기법 중 하나입니다.

 

Factory 클래스

public class EngineFactory {

  

  // 현대 엔진 클래스를 생산하여 반환

  public static Engine createHyundaiEngine() {

    return new HyundaiEngineVer2();

  }

 

  // 기아 엔진 클래스를 생산하여 반환

  public static Engine createKiaEngine() {

    return new KiaEngine();

  }

}

 

메서드를 static으로 함으로써 Factory 클래스를 생성하지 않아도 메서드 호출이 가능해졌습니다.

 

메인 클래스 (기본 생략)

 

// 엔진 생성

Engine hyundaiEngine1 = EngineFactory.createHyundaiEngine();

Engine hyundaiEngine2 = EngineFactory.createHyundaiEngine();

Engine kiaEngine1 = EngineFactory.createKiaEngine();

 

// 자동차 생산

Car car1 = new Car(hyundaiEngine1);

Car car1 = new Car(hyundaiEngine2);

Car car1 = new Car(kiaEngine1);

 

Factory 클래스를 사용함으로써, 인스턴스를 생성하는 클래스가 변경될 시 메서드의 내용물만 바꾸는 것으로 마무리 지을 수 있습니다. 

즉, 변경에 강한 애플리케이션이 되었습니다. 얏호!

 

여기까지가 주입의 이야기입니다. 

여기까지 이해하셨다면 이것으로 DI를 이해하는데 충분한 기반이 완성되었습니다.

 

다음 포스트에서는 DI에 대해서 구체적으로 알아보겠습니다.

 

 

'프로그래밍 > 스프링 부트' 카테고리의 다른 글

8. DI (4/4)  (0) 2020.06.18
7. DI (3/4)  (0) 2020.06.16
5. DI (1/4)  (0) 2020.06.14
4. 웹 애플리케이션 작성 (데이터 베이스로부터 값 취득)  (0) 2020.06.14
3. 웹 애플리케이션 작성 (파라미터 전달)  (0) 2020.06.14

DI란

드디어 스프링 코어인 DI에 대해서 설명해보겠습니다.

 

DI는 Dependency Injection (의존성 주입)의 약어입니다.

DI는 사용함에 있어서는 매우 간단하지만 스프링 전체의 기반이기 때문에 너무나 중요합니다. 

 

이해를 돕기위해 간단한 코드를 기재합니다만, 직접 작성하여 컴파일 할 필요는 없습니다.

 

DI를 한 단어로 설명하자면..

DI가 무엇인가에 대해 한 단어로 설명하자면, 인스턴스 관리입니다.

@AutoWired 어노테이션을 필드쪽에 붙이면 DI 컨테이너로부터 인스턴스를 취득합니다.

 

이미지

점점 그림이 추악해진다...

인스턴스 관리라고 말하면 막연하기 때문에 아래의 두가지를 한다고 생각해주세요.

 

1. 인스턴스의 생성

DI 컨테이너 안에서 인스턴스를 생성합니다. 즉, 클래스를 new 합니다.

그리고 애플리케이션에서는 그것들의 인스턴스를 취득하여 이용합니다.

 

DI안에서 매회 new를 한 인스턴스를 애플리케이션에 넘길 것인가, 아니면 한번 new 한 인스턴스를 애플리케이션에 넘길 것인가와 같은 것도 관리해줍니다.

 

2. 인스턴스의 라이프 사이클 관리

인스턴스의 라이프 사이클 관리를 간단히 코딩할 수 있도록 되어있습니다.

이것은 웹 애플리케이션 개발을 더욱더 편리하게 해줍니다. 

 

예를들어 서블릿의 요청 스코프(request scope)나 섹션 스코프(session scope)에 인스턴스를 간단히 등록가능하다는 뜻입니다.

 

인스턴스의 생성과 라이프 사이클 관리(인스턴스 파괴)를 DI가 해주기때문에, 클래스를 new 하던지, 사용이 끝난 변수에 null을 넣을 필요가 없어집니다. 이러한 이점때문에 null 처리를 깜빡했을 경우를 방지해주며 코드의 가독성도 높아집니다.

 

이건 어디까지나 DI를 간단하게 설명한 것입니다. 

하지만 이것을 알고있는 것만으로도 다음 설명에 이해 정도가 다를 것입니다.

 

보충 : new

자바에서 클래스를 new 하는 것은 인스턴스가 메모리에 올라간다는 의미입니다.

그러므로 너무 많이 new 를 해버리면, 그 만큼 메모리를 사용하게 됩니다.

 

이것이 안좋다라는 의미는 아닙니다만, 같은 페이지에 대량의 요청을(request) 처리하게 된다면 같은 클래스를 그 만큼 new 할 필요가 있습니다.

 

더욱이, new 를 한 이후에는 기본적으로 그 변수에 null 을 입력합니다. null 을 입력함으로써, 가비지 컬렉션이 메모리상의 인스턴스를 깨끗하게 청소해주고 메모리를 비워주기 때문입니다. 

 

DI를 이용한다면 기본적으로 null을 입력할 필요가 없습니다.

null을 넣지않으면 안되는 경우도 분명히 있습니다만 그건 추후에 설명하겠습니다.

 

DI 설명 전에...

먼저 DI를 이해하기 전에 필수 지식부터 설명드리고 있습니다.

이것을 이해한다면 DI를 간단하게 이해할 수 있기 때문입니다.

 

DI에 대해서 이해하기 위해,  DI (의존성 주입)을 의존성과 주입. 이 두가지를 분석하겠습니다.

그리고 이 정도 이해가 되신다면 DI에 대해서 거진 다 이해하실 수 있으실 겁니다.

 

의존성이란 무엇인가

애초에 자바에 있어 의존이라는게 무엇인가? 라는 것부터 설명하겠습니다.

의존이라고 하는 것은 다른 클래스를 이용하고 있는가와 같은 것 입니다.

 

1. 다른 클래스를 로컬 변수로써 가지고 있다.

2. 다른 클래스가 메서드의 파라미터, 반환 값으로 되어있다.

 

자동차를 예를 들어 설명해보겠습니다.

자동차에는 엔진이 있습니다. 물론 타이어라던지 여러가지도 있습니다만, 이해하기 편하게 엔진만 가지고 있는 자동차라고 가정해보겠습니다. 이 때의 코드는 아래와 같을 것입니다.

 

자동차 클래스 (현대)

public class Car {

 

 // 현대 엔진

 private HyundaiEngine hyundaiEngine;

 

 // 생성자

 public class Car(HyundaiEngine hyundaiEngine) {

   // 현대 엔진 설정

   this.hyundaiEngine = hyundaiEngine;

 }

}

 

이 자동차 클래스는 현재 엔진을 사용합니다. 

그리고 이 자동차 클래스를 만드는 (new) 코드는 다음과 같습니다.

 

메인 클래스 (기본 생략)

  

  // 부품 생산

  HyundaiEngine hyundaiEngine = new HyundaiEngine();

  // 자동차 생산

  Car car = new Car(hyundaiEngine);

 

클래스 다이어그램으로 표현하자면...

일부 생략했습니다. 중요한 포인트는 따로있기때문에..

클래스 다이어그램에는 클래스간의 관계를 표현한 다이어그램입니다. 

클래스 다이어그램에는 의존을 나타낼때 점선 화살표를 이용하여 표현합니다.

 

자동차가 엔진을 사용하기 위해 자동차 클래스에는 현대 엔진 클래스를 의존하고 있습니다.

예를 들어, 자동차의 최고속도는 엔진에 의해 결정됩니다. 즉, 차의 성능은 엔진에 의존하고 있기때문입니다.

그렇기 때문에 의존원 자동차로부터 의존처의 엔진을 점선 화살표로 이어지게 됩니다.

 

이와 같이 어느 클래스가 다른 클래스를 이용하고 있는 것이 바로 의존입니다.

그리고 의존은 '정도'가 있습니다.

 

예를 들어, 아까와 같은 자동차에서는 엔진을 교환하기 위해서는 현대의 같은 엔진만 이용할 수 밖에 없습니다.

좀더 연비가 좋은 엔진이 있어도 교환이 안됩니다. 혹시나 이 자동차에 현대 엔진이 아닌 기아 엔진을 사용하게 된다면, 아래와 같이 수정할 수 밖에 없습니다.

 

자동차 클래스 (기아)

public class Car {

 

 // 기아 엔진

 private KiaEngine kiaEngine;

 

 // 생성자

 public class Car(KiaEngine kiaEngine) {

   // 기아 엔진 설정

   this.kiaEngine= kiaEngine;

 }

}

 

메인 클래스 (기본 생략)

  

  // 부품 생산

  KiaEngine kiaEngine= new KiaEngine();

  // 자동차 생산

  Car car = new Car(kiaEngine);

 

부품 일부를 바꾸는 것이 아닌 자동차 클래스와 메인 클래스 전부 수정하지 않으면 안됩니다.

이걸로는 간단하게 부품을 교체할 수가 없습니다. 또한, 자동차 클래스를 테스트할 때는 기아 엔진 클래스가 완성되지 않으면 테스트를 진행할 수 없습니다. 이대로라면 테스트도 어렵고 변경에 취약한 애플리케이션이 되버립니다.

이와 같이 의존도가 높은 상태를 tight coupling. 즉 결합이 밀접하다고 합니다.

 

여기서 의존도를 낮추는 방법에는 자바의 인터페이스를 사용합니다.

인터페이스를 사용함에 있어서 자동차의 부품을 자유롭게 교체할 수 있게 됩니다.

 

엔진 인터페이스

public interface Engine {

  public void boot();  // 기동 메서드

  public void stop();  // 정지 메서드

}

 

엔진의 인터페이스는 기동 메서드와 정지 메서드를 준비해 보겠습니다. 

어느쪽도 전 엔진에 필요한 메서드입니다. 인터페이스를 상속한 클래스에는 반드시 해당 메서드를 코딩하지 않으면(오버라이드) 안됩니다. 안그러면 컴파일 에러가 발생합니다.

 

엔진 클래스 (현대)

public class HyundaiEngine implements Engine {

  // 생성자

  public HyundaiEngine() {

    super();

  }

 

  // 기동 메서드

  @Override

  public void boot() {

    System.out.println("현대 엔진 기동");

 

  // 정지 메서드

  @Override

  public void stop() {

    System.out.println("현대 엔진 정지");

}

 

엔진 인터페이스를 상속한 현대 엔진 클래스에는 기동과 정지시의 구체적인 처리가 적혀져 있습니다. 

덧붙여서 인터페이스를 상속한 클래스를 서브 클래스라고 합니다.

 

자동차 클래스

public class Car {

 

 // 엔진

 private Engine engine;

 

 // 생성자

 public class Car(Engine engine) {

   // 기아 엔진 설정

   this.engine= engine;

 }

 

 // 시동을 건다

 public void engineStart() {

   engine.boot();

 }

 

 // 시동을 잠근다

 public void engineStop() {

    engine.stop();

  }

}

 

자동차 클래스에는 필드를 인터페이스로 변경합니다. 그리고 인터페이스의 기동, 정지 메서드를 이용하는 메서드를 준비합니다.

 

메인 클래스 (기본 생략)

  

  // 엔진 생산 (현대 엔진)

  Engine engine = new HyundaiEngine ();

 

  // 자동차 생산

  Car car = new Car(engine);

 

  // 시동을 건다

  car.engineStart();

 

  // 시동을 잠근다

  car.engineStop();

 

메인 클래스에서는 Engine형의 변수에 현대 엔진의 인스턴스를 넣고있습니다.

인터페이스형의 변수에는 상속한 서브클래스의 인스턴스를 넣는 것이 가능합니다.

 

엔진의 동작을 확인하기 위해, 시동을 걸고 정지합니다. 이 실행 결과는 다음과 같습니다.

 

결과

현대 엔진 기동

현대 엔진 정지

 

현대 엔진 클래스의 메서드가 실행되고 있다는 것을 알 수 있습니다.

여기서 다시 클래스 다이어그램으로 가보면..

 

슬슬 그림에 한계가 보인다..

자동차 클래스는 엔진 인터페이스를 의존하고 있습니다만, 현대 엔진에는 의존하고 있지 않습니다.

자동차 클래스의 점선은 엔진 인터페이스에만 향하고 있습니다. 

여기서 기아 엔진을 사용하고 싶을 경우에는 기아 엔진 클래스를 준비하여 메인 클래스를 조금 수정함에 있어 간단하게 끝납니다. 즉 자동차 클래스는 수정하지 않습니다.

 

엔진 클래스 (기아)

public class KiaEngine implements Engine {

  // 생성자

  public KiaEngine() {

    super();

  }

 

  // 기동 메서드

  @Override

  public void boot() {

    System.out.println("기아 엔진 기동");

 

  // 정지 메서드

  @Override

  public void stop() {

    System.out.println("기아 엔진 정지");

}

 

메인 클래스 (기본 생략)

  

  // 엔진 생산 (기아 엔진)

  Engine engine = new KiaEngine();

 

  // 자동차 생산

  Car car = new Car(engine);

 

  // 시동을 건다

  car.engineStart();

 

  // 시동을 잠근다

  car.engineStop();

 

메인 클래스에는 기아 엔진 클래스를 생성 (new) 하여 변경하고 있습니다.

그 결과는 아래와 같습니다.

 

결과

기아 엔진 기동

기아 엔진 정지

 

이와 같은 경우의 클래스 다이어그램을 다시 그리자면...

기아 엔진 추가

주목해야 할 부분은 기아 엔진을 추가해도 자동차 클래스의 의존은 오직 엔진 인터페이스만 의존하고 있습니다.

즉, 엔진 클래스를 추가하고 싶어도 자동차 클래스는 일절 변경을 하지않아도 된다는 것입니다. (오호!)

또한, 자동차 클래스의 테스트를 진행할려고 하면, 엔진 인터페이스를 상속한 더미 클래스를 준비하여 테스트를 진행할 수 있게 되었습니다.

 

이와 같이 인터페이스를 사용하면 의존'정도'를 낮출 수 있습니다. 

이와 같이 의존도가 낮은 상태를 loose coupling. 즉 결합이 느슨하다고 합니다.

 

자바의 인터페이스에 대한 얘기가 되었습니다만, 여기까지가 의존성의 얘기가 됩니다.

 

정리하자면...

1. 의존이라는 것은 타 클래스를 이용하고 있다는 것을 말한다.

2. 자바의 인터페이스를 사용함에 있어, 의존'정도'를 낮추는 것이 가능하다. (결합이 느슨하다.)

 

다음 포스트에서는 주입에 대해서 설명해보도록 하겠습니다.