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

[둘리] 1단계 자동 DI 미션 제출합니다 #5

Merged
merged 18 commits into from
Sep 5, 2023

Conversation

hyemdooly
Copy link

안녕하세요. 베르~ 반갑습니다.
수동 DI 외에 고민해본 적이 별로 없어서 조금 어려웠네요.
ViewModelFactoryRepositoryModule를 생성하여 일관적으로 ViewModel을 생성할 수 있도록 작성해봤습니다.
나중에는 Room을 사용하는 것 같아 Application단에서 이 Repository를 해결해보고 싶었는데 쉽지 않더라고요.
우선 현재의 요구 사항을 충족시키기위해 RepositoryModule Object를 생성하여 Repository 구현체들을 모아두었습니다!
추가 구현 사항은 리뷰 후에도 시간이 남으면 해보겠습니다.🥲
리뷰 잘 부탁드립니다. :)

ViewModelFactory

class ViewModelFactory : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val constructor = modelClass.declaredConstructors.first() // 정의된 첫번째 생성자 가져오기
        require(constructor != null) { IllegalArgumentException("Unknown ViewModel Class $modelClass") }

        val types = constructor.parameterTypes // 생성자의 파라미터 타입들 모두 가져오기
        val params = mutableListOf<Any?>() // 파라미터에 담아줄 객체들을 담을 리스트

        val properties = RepositoryModule::class.java.declaredFields // RepositoryModule에 정의되어있는 모든 필드들 가져오기
        for (type in types) {
            val field = properties.first { it.type == type }
                ?: throw IllegalArgumentException("Can't find Property $type") // type과 같은 type의 property 가져오기
            field.isAccessible = true // 접근제어자 바꿔주기
            params.add(field.get(null))
        }

        return constructor.newInstance(*params.toTypedArray()) as T // ViewModel 객체 생성
    }
}

Copy link
Member

@SeongHoonC SeongHoonC left a comment

Choose a reason for hiding this comment

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

안녕하세요. 둘리! 잘부탁드립니다ㅎㅎ
자동 DI 잘 구현해 주었어요!
다만 테스트가 없어서 조금 아쉽네요ㅜ
리뷰 확인해주세요!

class ViewModelFactory : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
val constructor = modelClass.declaredConstructors.first()
require(constructor != null) { IllegalArgumentException("Unknown ViewModel Class $modelClass") }
Copy link
Member

Choose a reason for hiding this comment

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

requireNotNull 을 활용해 보는게 어떨까요?

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 20
val params = mutableListOf<Any?>()

val properties = RepositoryModule::class.java.declaredFields
for (type in types) {
val field = properties.first { it.type == type }
?: throw IllegalArgumentException("Can't find Property $type")
field.isAccessible = true
params.add(field.get(null))
}
Copy link
Member

Choose a reason for hiding this comment

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

가변 리스트와 for 문이 아닌 아닌 map 을 활용하는 것이 더 코틀린스럽지 않을까요?

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
Author

Choose a reason for hiding this comment

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

알고리즘 문제 푸는 것에 뇌가 절여져서 map 쓸 생각을 못했네요...

Copy link
Author

Choose a reason for hiding this comment

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

수정했습니다..!!! 제가 kotlin reflection이 안됐던 이유가 reflect를 import안해줘서임을 깨닫고 자바 reflection을 걷어내고 kotlin으로 바꿔줬습니다!
수업시간에 배운 내용들이긴 하지만 비슷해서 싹 바꿨어요!

Comment on lines 8 to 11
object RepositoryModule {
val productRepository: ProductRepository = ProductRepositoryImpl()
val cartRepository: CartRepository = CartRepositoryImpl()
}
Copy link
Member

Choose a reason for hiding this comment

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

Repository 가 추가될 때 재사용 가능하게 만들어 보면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

Container로 변경하고, 프로퍼티로 map을 추가해 instance를 추가하고 가져올 수 있게 했습니다.

Copy link
Member

@SeongHoonC SeongHoonC left a comment

Choose a reason for hiding this comment

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

수업시간에 배운 내용을 빠르게 적용한 둘리 대단합니다!
고민해볼만한 코멘트 한 개 남겼는데 다음 미션에서 생각해 보셨으면 좋겠어요!
1단계 이만 머지하겠습니다ㅎㅎ

Comment on lines +5 to +16
object Container {
private val instances = mutableMapOf<KClass<*>, Any>()
fun addInstance(type: KClass<*>, instance: Any) {
instances[type] = instance
}

fun getInstance(type: KClass<*>): Any =
instances[type] ?: throw NoSuchElementException("Unknown Instance")

fun clear() {
instances.clear()
}
Copy link
Member

Choose a reason for hiding this comment

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

어디서나 접근할 수 있는 object 로 관리하면 instance 의 무결성을 보장할 수 없다고 생각합니다! 다음 미션에 참고해주세요!

Comment on lines +17 to +18
Container.addInstance(CartRepository::class, CartRepositoryImpl())
Container.addInstance(ProductRepository::class, ProductRepositoryImpl())
Copy link
Member

Choose a reason for hiding this comment

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

이제 생성되는 저장소가 추가되어도 유연하게 대응할 수 있겠네요!

@SeongHoonC SeongHoonC merged commit e3a8355 into woowacourse:hyemdooly Sep 5, 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.

None yet

2 participants