ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • DI (Dependency Injection) : 의존성 주입
    디자인패턴 2020. 12. 5. 23:51
    728x90

    1. 의존성 (Dependency) 

    class Americano {...}
    
    class Programmer {
        private Americano americano;
    
        public Programmer() {
        	this.americano = new Americano();
        }
        
        public startProgramming() {
        	this.americano.drink();
            ...
        }
    }

     

    1) Programmer 클래스는 Americano 클래스에 의존성을 가지고 있다.

    새로운 Coffee 를 마시고 싶다면, Americano 클래스의 내용을 바꾸거나 새로운 클래스를 생성해서 작업해야 한다.

     

    class Americano implements Coffee {...}
    class Cappuccino implements Coffee {...}
    
    class Programmer {
        private Coffee coffee;
    
        public Programmer() {
            this.coffee = new Americano();
            // or
        	this.coffee = new Cappuccino();
        }
        
        public startProgramming() {
        	this.coffee.drink();
            ...
        }
    }

     

    2) OOP (객체지향) 에 맞게 Coffee 인터페이스 참조를 이용하였다. 

    비교적 수정할 부분이 적어진 것 같으나 여전히 Programmer 클래스가 이번에는 Cappuccino 클래스에 의존적이게 된다. 이렇게 내부에서 new로 객체를 생성하여 구체적인 타입이 결정되어 버리면 구현 클래스에 여전히 의존적이게된다.

     

    문제점

    • 두 객체 간의 긴밀한 결합 (Tight Coupling) 이 생긴다 => Coffee 객체가 변경되면 Programmer 객체도 변경된다. 하나의 모듈이 변경되면, 의존한 모듈까지 변경되어야 한다.
    • 새로운 Coffee 클래스를 사용하기 위해서는 Programmer 클래스를 수정해야한다.=> 코드의 재사용성이 떨어진다.
    • 실제 객체를 모의 객체로 대체하기 어렵기 때문에 Unit Test 작성이 어려워지게 된다.

     

    2. 의존성 주입 (DI; Dependency Injection)

    필요한 클래스를 직접 생성하는 것이 아니라, 외부에서 객체를 생성하여 넘겨준다

    왼쪽은 A에서 B,C를 생성하는 일반적인 의존 형태이고, 오른쪽은 외부에서 의존 객체를 생성하고 주입하는 형태이다

     

    public class Cappuccino implements Coffee {...}
    public class Latte implements Coffee {...}
    
    public class Programmer {
        private Coffee coffee;
        
        public Programmer(Coffee coffee) {
            this.coffee = coffee;
        }
    }

    Programmer 클래스는 Coffee 클래스 제공에 대한 책임을 외부 코드(주입자)로 위임한다. 따라서 Programmer 클래스는 주입자와 서비스 구성 방식 또는 사용중인 실제 서비스에 대해 알 필요가 없다. 서비스의 사용 방식을 정의하고 있는 서비스의 고유한 인터페이스에 대해서만 알면 된다.

     

    의존성 주입은 프로그램 디자인이 결합도를 느슨하게 되도록하고 의존관계 역전 원칙과 단일 책임 원칙을 따르도록 클라이언트의 생성에 대한 의존성을 클라이언트의 행위로부터 분리하는 것이다

     

    1) 의존성 주입은 네 가지 역할을 포함

    • 사용될 서비스 객체
    • 사용하는 서비스에 의존하는 클라이언트 객체
    • 클라이언트의 서비스 사용 방법을 정의하는 인터페이스 => 클라이언트는 의존성의 특정 구현에 대한 구체적인 지식이 필요 없다. 인터페이스의 이름과 API만 알면 된다. 결과적으로 인터페이스가 변경되더라도 클라이언트는 수정할 필요가 없어진다.
    • 서비스를 생성하고 클라이언트로 주입하는 책임을 갖는 주입자

    2) 장점

    • 클라이언트의 구성 가능성을 유연하게 해준다. 클라이언트의 행위는 고정되어 있다. 클라이언트는 클라이언트가 기대하는 고유한 인터페이스를 지원하는 모든 것을 할 수 있다.
    • 클라이언트는 더 독립적이며 테스트에 속하지 않은 다른 객체를 가장하는 stubs 또는 Mock 객체를 사용해 독립된 Unit Test가 더 쉬워지는 결과를 얻는다.
    • 클라이언트는 사용해야하는 모든 구체적인 구현에 대한 지식을 제거할 수 있다. 디자인 변경이나 결함의 영향으로부터 클라이언트를 독립하는데 도움을 주며, 이는 재사용성, 테스트가능성, 유지가능성을 향상시킨다

     

    그러나 의존성 파라미터가 많아지면 보일러 플레이트 코드가 많아질 수 있다. 따라서 이를 위해 DI 라이브러리를 사용할 수 있다.

     

    3) DI Framework

    DI를 위해서는 객체를 생성하고 넘겨주는 외부의 무언가가 필요하다. 이것이 DI Framework가 하는 일이다. 외부에서 넘겨주는 무언가를 스프링에서는 컨테이너, Dagger에서는 Component와 Module이라고 부른다.

    DI는 이렇게 의존성이 있는 객체의 제어를 외부 Framework로 올리면서 IoC (Inversion of Control, 제어의 역전) 개념을 구현한다. 

     

    4) Android의 DI 라이브러리

    • Dagger
    • Koin

     

    5세의 의존성 주입
    스스로 냉장고로 가서 무언가를 가져올 때 문제가 발생할 수 있다. 문을 열어 놓고 갈수도 있고, 엄마나 아빠의 물건을 가져갈 수도 있다. 심지어 있지도 않은 물건이나 유효기간이 지난 것을 찾고 있을 수도 있다.
    필요한 것을 정의해야한다. "나는 점심이랑 같이 마실 뭔가가 필요해", 그 후에 뭔가를 가져왔는지 확인하고 앉아서 먹으면 된다.
    John Munsch, 28 October 2009

     

     

     

    디자인패턴 - SOLID원칙 보기

    2020/12/12 - [디자인패턴] - [디자인패턴] SOLID 원칙 : 객체지향 개발 5대 원칙

     

    [디자인패턴] SOLID 원칙 : 객체지향 개발 5대 원칙

    SOLID 원칙 로버트 마틴이 명명한 객체지향 프로그래밍 및 설계 기본 5대 원칙 1. SRP (Single Responsibility principle; 단일 책임 원칙) 1) 정의 : 한 클래스는 하나의 책임만 가져야 한다. 2) 설명 로버..

    waves123.tistory.com

     

     

     

     

    참고

    728x90

    '디자인패턴' 카테고리의 다른 글

    [디자인패턴] SOLID 원칙  (0) 2020.12.12
Designed by Tistory.