Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[스캇] 4단계 자동 DI 미션 제출합니다 #61

Merged
merged 5 commits into from
Sep 25, 2023

Conversation

chws0508
Copy link

안녕하세요 Ring Ring! 항상 좋은 리뷰 감사드려요!!
개인적으로 이번 미션 너무 어려웠네요ㅠㅠ 그래서 선택 요구사항은 만족하지 못하였습니다!
저의 코드 흐름에 대해 간략하게 설명해드리겠습니다!

Module

먼저 Module 에 주입하고 싶은 의존성 객체들을 함수를 통해 정의합니다! 여기서 주입하고 싶은 타입이 함수의 ReturnType 이 되게 되고, 실행문이 그 ReturnType 의 객체가 됩니다.

DiContainer

현재 사용되고 있는 의존성 객체들을 캐싱해놓는 곳입니다. 싱글톤 객체들은 Application 이 onCreate 될 때 DiContainer 에 저장하고, 파괴되지 않습니다. 다른 스코프 객체들은 그 객체의 생명주기 동안 저장되고 생명주기가 끝나면 삭제합니다.

Dependency

모듈에 정의된 함수를 객체로 관리한다고 생각하시면 됩니다. 이 Dependency의 getInstance와 getParamsInstances를 통해 재귀 의존성 주입이 가능합니다.

Singleton

  • 모듈에 있는 함수에 singleton Annotation 이 붙으면 Singleton 의존성 객체를 생성한다는 의미로, DiApplication이 onCreate 될 때 DiContainer 에 정의되고 앱이 꺼질때 까지 파괴되지 않습니다.

ActivtiyScope

  • 모듈에 있는 함수에 ActivityScope Annotation이 붙으면 Activity 생명주기에 의존하는 의존성 객체를 생성한다는 의미로, DiAppComponentActivity가 생성될 때, DiContainer에 저장됩니다. 여기서 DiAppComponent에 주입될 수 있는 객체만 DiContainer에 저장되고, Activtiy가 onDestroy일 때 DiContainer에서 제거한다.

ViewModelScope

  • 모듈에 있는 함수에 ViewModelScope Annotation이 붙으면 ViewModel 생명주기에 의존하는 의존성 객체를 생성한다는 의미로, DiViewModel이 생성될 때, DiContainer에 저장됩니다. 여기서 DiViewModel에 주입될 수 있는 객체만 DiContainer에 저장되고, ViewModel이 onCleared일 때 DiContainer에서 제거한다. 그리고 ViewModel 은 필드주입은 개인적으로 필요 없다고 생각하기 때문에, 구현하지 않았습니다. 그 이유는 Activity는 생성자 주입이 불가능해서 필요하지만, ViewModel 은 생성자로 가능하기 때문이다.

  • 이 외에 궁금한 점이 있으시면 Dm 부탁드려요!

  • 아 그리고 블핑 콘서트 간거 부럽네요 ㅠ

@chws0508 chws0508 self-assigned this Sep 19, 2023
Copy link
Member

@RightHennessy RightHennessy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 scottttttttttt ~
확실히 코드가 가독성이 좋아서 리뷰하기 좋네요 👍
테스트도 성공 / 실패 테스트 모두 적어주셔서 좋았습니다 ㅎㅎ
오늘 수업에서 설명하신 테스트도 추가해보면 좋을 것 같아요 !

image

Comment on lines 27 to 46
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
loadActivityScopeDependencies()
injectFields()
}

override fun onPause() {
super.onPause()
dependencies.forEach { DiContainer.destroyDependency(it) }
}

override fun onResume() {
super.onResume()
dependencies.forEach { DiContainer.addDependency(it) }
}

override fun onDestroy() {
super.onDestroy()
dependencies.forEach { DiContainer.destroyDependency(it) }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dependencies들을 addDependency 하는 과정을 onCreate(), onResume()
그리고 destroyDependency 하는 과정을 onPause, onDestory
이렇게 두번씩 하는 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 현재 구조에서는 A 엑티비티가 죽지 않은상태로 B엑티비티가 실행되면, 새로운 객체를 주입하지않고 같은 의존성을 주입하게 됩니다ㅠ 따라서 onpause에서 해제하고 다시 onResume에서 다시 주입하는 형태입니다

kClazz: KClass<*>,
annotation: Annotation?,
): Dependency {
values.forEach { println("Scott ${it.typeClass} ${kClazz} ${it.qualifierAnnotation} ${annotation}") }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

선생님.. print 어디에 쓰시게요..?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅎㅎ...

Comment on lines +37 to +44
fun KParameter.getQualifierAnnotation() =
annotations.firstOrNull { it.annotationClass.hasAnnotation<Qualifier>() }

fun KProperty<*>.getQualifierAnnotation() =
annotations.firstOrNull { it.annotationClass.hasAnnotation<Qualifier>() }

fun KFunction<*>.getQualifierAnnotation() =
annotations.firstOrNull { it.annotationClass.hasAnnotation<Qualifier>() }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

깔끔하네요 👍
저는 이걸 하나도 어떻게 합치지 고민했었는데, 이 정도로만 해도 깔끔해보이네요

import kotlin.reflect.full.hasAnnotation

open class DiViewModel : ViewModel() {
private val module = DiApplication.module
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DiViewModel의 module이 DiApplication의 module을 가는 이유가 무엇인가요?
DefaultModule 하나로만 관리하면 Module이 너무 비대해지지 않을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 모듈로 관리하려 했는데 쉽지 않네용ㅠㅠ

Comment on lines +12 to +15
data class Dependency(
private val module: Module,
private val function: KFunction<*>,
val context: Context? = null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependecy가 모듈 자체를 들고 있네용...
현재 구조에서는 Module이 하나인걸로아는데, 한개인 경우라면 Dependency data class는 조금 비효율적으로 느껴지기도 하네용... 스캇의 생각은 어떠신가요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 여러 모듈을 하려고 이렇게 설계 했는데, 여러 모듈로 하려니 쉽지 않네요ㅠㅠ 하지만 의존성 객체를 생성하기 위해선 모듈이 꼭 필요해서 구조를 바꾸긴 힘들 것 같습니다

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 모듈을 관리하는게 생각보다 어렵더라고요..

Copy link
Member

@RightHennessy RightHennessy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스캇 ~ DI 미션동안 고생 많으셨습니다 ㅎㅎ
예전에 같이 페어 했던 게 어제 같은데..
그 사이에 많이 성장하셨다고 느껴졌습니다. !
DI 미션은 이정도로 충분한 것 같아 이만 머지하도록 하겠습니다 ~!

@RightHennessy RightHennessy merged commit ebbac2d into woowacourse:chws0508 Sep 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants