[Android] BaseActivity를 사용하는 당신, 이 글을 보세요 - Delegation

0

Android

목록 보기
16/16

Don't Use 'BaseXXX.kt' Anymore !

안드로이드 프로젝트를 진행하다 보면 일부 코드를 재사용하기 위해 BaseClass를 상속받아 사용하는 경우가 있었습니다. BaseActivity, BaseFragment, BaseViewModel, BaseListAdapter, BaseDialog 등등..

소규모 프로젝트에서는 다소 편리할 수도 있지만, 이는 생산성이 떨어지는 안티패턴입니다. 그 이유는 다음과 같습니다.

  1. 객체 지향 원칙인 단일 책임 원칙에 위배됩니다. Base Class의 내부를 보면 책임이 분리되지 않은 여러 팀장급(?)의 메서드들이 모여있습니다.
  2. Big God Class입니다. 이를 상속받는 child class 가 많아질 수록 공통으로 편리하게 쓰기 위해 base에는 더 많은 변수, 메서드를 사용하게 됩니다.
  3. 2번의 이유로 인해, child class 에서 base 클래스 내에 있는 일부 코드는 전혀 사용되지 않을 수 있습니다.
  4. 공통으로 쓰는만큼, 변경하게 된다면, 많은 사이드이펙트에 직면하게됩니다. (이를 방지하기 위해 코틀린에서는 기본적으로 상속을 금지하고, 굳이 하고 싶으면 open키워드를 사용해야합니다.)

일반적으로 코드를 재사용해야한다면, 클래스간의 여러 관계(Relationships)를 알아야합니다.

1. 상속(Inheritance)
다른 곳으로 부터 클래스를 얻는 관계입니다. 예를 들자면 개(Dog)는 동물(Animal)이다 처럼 is-a로 표현합니다. 객체지향 프로그래밍에서는 다중 상속을 금지하고 있습니다.

2. 연관(Association)
한 쪽이 다른 한쪽의 일부분인 관계입니다. 예를 들어 엔진을 가지고 있는 자동차 처럼 has-a로 표현합니다.

연관 관계를 마치 상속 처럼 이용할 수 있을까?

Kotlin의 Delegation을 사용하면 됩니다. 특정 클래스가 필요로 하는 기능들만을 각각 위임하는것이죠.

예를들어, 퍼미션을 요청하는 메서드를 액티비티에 위임하고 싶다면 다음과 같이 작성합니다.

interface PermissionDelegation {
    fun requestPermission(context: Context, permission: String)
}

class PermissionDelegationImpl : PermissionDelegation {
    override fun requestPermission(context: Context, permission: String) {
        val permissionListener: PermissionListener = object : PermissionListener {
            override fun onPermissionGranted() {
                //권한요청성공
            }

            override fun onPermissionDenied(deniedPermissions: List<String>) {}
        }
        TedPermission.with(context)
            .setPermissionListener(permissionListener)
            .setRationaleMessage(context.resources.getString(R.string.permission_3))
            .setDeniedMessage(context.resources.getString(R.string.permission_1))
            .setPermissions(Manifest.permission.ACCESS_FINE_LOCATION)
            .check()
    }
}

이렇게 하면 확연히 책임이 분리된 것을 볼 수 있습니다.

이제 Kotlin의 by키워드를 사용하여 간단하게 퍼미션 요청기능을 위임할 수 있습니다.

class MainActivity : AppCompatActivity(),
    PermissionDelegation by PermissionDelegationImpl() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        ...
    }
    ...
}

이렇게 필요한 기능들을 각각 위임하게 된다면, 책임이 분리되어 간결해지고 디버깅도 쉬워집니다.

References

https://kotlinlang.org/docs/delegation.html
https://prokash-sarkar.medium.com/delegation-pattern-an-effective-way-of-replacing-androids-baseactivity-with-native-kotlin-support-b00dee007d69
https://medium.com/@mobidroid92/hello-delegates-goodby-base-classes-c8aeedc2b855

0개의 댓글