-
의존성 주입Android/아키텍처를 알아야 앱 개발이 보인다 2023. 3. 18. 18:42
https://developer.android.com/training/dependency-injection?hl=ko
Android의 종속 항목 삽입 | Android 개발자 | Android Developers
Android의 종속 항목 삽입 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 종속 항목 삽입(DI)은 프로그래밍에 널리 사용되는 기법으로, Android 개발에 적합합니
developer.android.com
- 의존성 Dependency
- A가 B를 의존한다 -> B에 변화가 생기면 A에 영향을 끼친다.
- ex) 요리는 레시피에 의존한다 -> 레시피에 변화가 생기면 요리에 영향을 끼친다.
- 주입 Injection : 생성자나 메서드를 통해 외부로부터 생성된 객체를 받는것.
- 의존성 주입 : 의존 관계에 있는 클래스의 객체를 외부로 부터 생성하여 주입받는것. Car와 engine으로 예시를 들어보자.
아래는 클래스 간 의존성 주입의 예시이다.
// 1. 클래스 자체에 종속항목을 구성한다. class Car { private val engine = Engine() fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.start() } // 2. 다른 곳에서 부터 객체를 가져온다. , 생성자 이용 class Car(private val engine: Engine) { fun start() { engine.start() } } fun main(args: Array) { val engine = Engine() val car = Car(engine) car.start() } // 3. 객체를 매개변수로 받아온다. , 메소드 이용 class Car { lateinit var engine: Engine fun start() { engine.start() } } fun main(args: Array) { val car = Car() car.engine = Engine() car.start() }
- 클래스 자체에 종속 항목 구성
- Car 클래스 자체가 Engine을 구성한다. Car 클래스 내부에서 Engine 클래스의 인스턴스를 생성하고, 자체적으로 관리하는 방식
- Car와 Engine이 밀접하게 연결되어 있어 서브클래스 및 구현을 쉽게 할수 없다. -> 예를 들어서 전기 엔진 혹은 가솔린 엔진의 차를 구현하려면 새로 두가지 유형의 Car를 생성해야 한다.
- Car 클래스와 Engine 클래스 간의 결합도가 높아지기 때문에, 유지보수나 확장성이 낮아질 수 있다.
- 객체 가져오기 - 생성자 주입
- Car 클래스 생성자에서 Engine 인스턴스를 외부에서 받아오는 방식으로, 의존성을 외부로부터 주입받는 것
- main 함수에서 Car를 사용한다. Car는 Engine에 종속 되므로 앱은 Engine 인스턴스를 생성후 이를 사용해 Car 인스턴스를 구성한다.
- 이로 인해서 Car를 재사용할 수 있고, Engine의 다양한 구현을 Car에 전달 할 수있다.
- Car 클래스 내부에서 Engine 클래스의 인스턴스를 생성하지 않으므로, 결합도가 낮아지고, 유지보수나 확장성이 높아질 수 있다.
- 매개변수로 객체 받아오기 - 메소드 주입
- Car 클래스에서 Engine 인스턴스를 선언하지 않고, start() 메서드에서 Engine 인스턴스를 매개변수로 받아오는 방식
- 2번과 마찬가지로 외부에서 Engine 인스턴스를 받아와 사용하므로, 결합도가 낮아지고 유지보수나 확장성이 높아질 수 있다.
- Engine 인스턴스가 빈번하게 변경되거나 업데이트되는 경우, 매번 start() 메서드를 호출할 때마다 Engine 인스턴스를 매개변수로 넘겨주어야 한다.
주로 2,3의 방법을 주로 사용한다.
- 변경의 전이 : 객체 간의 의존성을 느슨하게 결합시키는 원칙
- 상위 수준 모듈은 하위 수준 모듈의 구현에 의존하지 않고, 추상화에 의존해야 한다는 원칙 (상위는 interface나 abstract class로, 하위는 class로 구현)
- Computer의 CPU나 Car의 Engine이 변경되게 되면 (예로, 이름을 CPU_1,Engine_1로 변경하면) 이는 의존 관계에 있는 Computer와 Car에 영향을 끼친다. 이를 해결하기 위해서 CPU나 Engine을 interface로 변경 할 수있다.
interface Engine { fun start() } class GasolineEngine : Engine { override fun start() { println("Gasoline engine starts.") } } class ElectricEngine : Engine { override fun start() { println("Electric engine starts.") } } class Car(private val engine: Engine) { fun start() { engine.start() } } fun main(args: Array<String>) { val engine = GasolineEngine() val car = Car(engine) car.start() }
Car 클래스가 Engine 인터페이스에만 의존하도록 하여, GasolineEngine 클래스나 ElectricEngine 클래스의 구현 방식이 변경되더라도 Car 클래스는 수정하지 않아도 된다.
- 제어의 역전 : 객체가 자신이 사용할 객체를 직접 생성하거나 관리하지 않고, 외부에서 객체를 생성하고 관리하는 것
- 외부로 부터 객체를 생성하여 이를 생성자 또는 매개변수로 제공받는다.
- 제어의 역전을 적용하기 전에는 자체 클래스 내부에서 객체를 생성하고 관리 했으나, 적용 후에는 객체의 생성 및 관리를 외부에서 담당하게 된다.
- 이를 통해서 결합도가 약해지고, 클래스는 객체의 변경사항이 있어도 내부 나 매개 변수를 변경하지 않아도 된다.
interface Service { fun doSomething() } class ServiceImpl : Service { override fun doSomething() { println("Doing something...") } } class Client(private val service: Service) { fun execute() { service.doSomething() } } fun main() { val service = ServiceImpl() val client = Client(service) client.execute() }
- Client 클래스가 Service 인터페이스에 의존한다 , Client 클래스의 생성자에서 Service 인터페이스를 받아서 멤버 변수로 저장한다.
- 의존하는 객체를 외부에서 주입받게 되면, Client 클래스 내부에서 Service 구현체를 직접 생성하거나 참조하는 것이 아니라, 외부에서 주입받은 객체를 사용하여 메서드를 호출 -> 의존성 주입
- Client 클래스는 Service 인터페이스에만 의존하고 있으며, 구체적인 구현체(ServiceImpl)에는 의존하지 않습니다. 이렇게 의존성을 느슨하게 결합시키는 것이 제어의 역전(Inversion of Control)
- Client 클래스는 Service 인터페이스를 사용하므로, Service 인터페이스를 구현하는 다른 클래스를 주입하면 Client 클래스의 동작이 바뀌게 된다.
- 의존성 주입의 장단점
- 장점
- 인터페이스를 기반으로 작성되어 코드가 유연해진다.
- 주입하는 코드만 변경하면 되므로, 유지보수가 편해진다.
- 의존성 주입 객체를 stub이나 mock등의 객체로 사용할수 있어 단위테스트가 쉬워진다.
- 클래스간 결합도가 느슨해 진다.
- 인터페이스 기반으로 작성되어 여러 개발자가 이를 통해 독립적으로 클래스를 개발할수 있다. -> 클래스간의 의존하는 인터페이스만 알면 된다.
- 단점
- 번거롭다.
- 동작과 구성을 분리해서 코드 추적이 힘들다.
- dagger2 사용시 시간이 더 걸린다.
- 장점
'Android > 아키텍처를 알아야 앱 개발이 보인다' 카테고리의 다른 글
클린 아키텍처 (1) 2023.03.18 애플리케이션 설계 - SOLID 원칙 (0) 2023.03.18 - 의존성 Dependency