-
Notifications
You must be signed in to change notification settings - Fork 25
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
Changes from 7 commits
029b9ca
66591f0
2472367
8fa65de
cf756b3
e75d7cc
aab65d6
3f39cc3
072ac94
6fd5134
984ab03
ddfe49a
53b47d0
b84e79d
ee21ff5
abb5186
42ad01c
254e9bc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,31 @@ | ||
# android-di | ||
# 0.5단계 | ||
## 기능 요구 사항 | ||
### 생성자 주입 - 수동 | ||
다음 문제점을 해결한다. | ||
|
||
- [x] DB 없이 테스트하기 어렵다. | ||
- [x] DB 객체를 교체하기 위해 또다른 객체를 만들어 바꿔줘야 한다. 즉, ViewModel에 직접적인 변경사항이 발생한다. | ||
|
||
# 1단계 | ||
## 기능 요구 사항 | ||
### 생성자 주입 - 자동 | ||
다음 문제점을 해결한다. | ||
|
||
- [x] ViewModel에서 참조하는 Repository가 정상적으로 주입되지 않는다. | ||
- [x] Repository를 참조하는 다른 객체가 생기면 주입 코드를 매번 만들어줘야 한다. | ||
- [x] ViewModel에 수동으로 주입되고 있는 의존성들을 자동으로 주입되도록 바꿔본다. | ||
- [x] 특정 ViewModel에서만이 아닌, 범용적으로 활용될 수 있는 자동 주입 로직을 작성한다. (MainViewModel, CartViewModel 모두 하나의 로직만 참조한다) | ||
- [x] 100개의 ViewModel이 생긴다고 가정했을 때, 자동 주입 로직 100개가 생기는 것이 아니다. 하나의 자동 주입 로직을 재사용할 수 있어야 한다. | ||
- [x] 장바구니에 접근할 때마다 매번 CartRepository 인스턴스를 새로 만들고 있다. | ||
- [x] 여러 번 인스턴스화할 필요 없는 객체는 최초 한 번만 인스턴스화한다. (이 단계에서는 너무 깊게 생각하지 말고 싱글 오브젝트로 구현해도 된다.) | ||
|
||
## 선택 요구 사항 | ||
- [ ] TDD로 DI 구현 | ||
- [ ] Robolectric으로 기능 테스트 | ||
- [ ] ViewModel 테스트 | ||
- [ ] 모든 도메인 로직, Repository 단위 테스트 | ||
|
||
## 프로그래밍 요구 사항 | ||
사전에 주어진 테스트 코드가 모두 성공해야 한다. | ||
Annotation은 이 단계에서 활용하지 않는다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package woowacourse.shopping.ui.common | ||
|
||
import woowacourse.shopping.data.CartRepository | ||
import woowacourse.shopping.data.CartRepositoryImpl | ||
import woowacourse.shopping.data.ProductRepository | ||
import woowacourse.shopping.data.ProductRepositoryImpl | ||
|
||
object RepositoryModule { | ||
val productRepository: ProductRepository = ProductRepositoryImpl() | ||
val cartRepository: CartRepository = CartRepositoryImpl() | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package woowacourse.shopping.ui.common | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.ViewModelProvider | ||
|
||
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") } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. requireNotNull 을 활용해 보는게 어떨까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 좋아용 수정했습니다~! |
||
|
||
val types = constructor.parameterTypes | ||
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)) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 가변 리스트와 for 문이 아닌 아닌 map 을 활용하는 것이 더 코틀린스럽지 않을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추가로 함수 분리가 필요할 것 같아요ㅎㅎ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 알고리즘 문제 푸는 것에 뇌가 절여져서 map 쓸 생각을 못했네요... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수정했습니다..!!! 제가 kotlin reflection이 안됐던 이유가 reflect를 import안해줘서임을 깨닫고 자바 reflection을 걷어내고 kotlin으로 바꿔줬습니다! |
||
|
||
return constructor.newInstance(*params.toTypedArray()) as T | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package woowacourse.shopping.data | ||
|
||
import woowacourse.shopping.model.Product | ||
|
||
interface CartRepository { | ||
fun addCartProduct(product: Product) | ||
|
||
fun getAllCartProducts(): List<Product> | ||
|
||
fun deleteCartProduct(id: Int) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package woowacourse.shopping.data | ||
|
||
import woowacourse.shopping.model.Product | ||
|
||
interface ProductRepository { | ||
fun getAllProducts(): List<Product> | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository 가 추가될 때 재사용 가능하게 만들어 보면 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Container로 변경하고, 프로퍼티로 map을 추가해 instance를 추가하고 가져올 수 있게 했습니다.