[Kotlin Design Class] Adapter Pattern

0

Kotlin Design Class

목록 보기
4/4

Android를 개발하다보면 Adapter에 대해 많이 들어봤을것입니다.

예를들면, RecyclerView를 구현할때 setAdapter()을 할때 말이죠.

Adapter는 정확히 무엇일까요?

어뎁터를 사용하면, 호환되지 않는 두 인터페이스가 함께 작동할 수 있습니다.
인터페이스는 호환 되지 않을수 있으나, 내부 함수들은 유사한 기능을 하고 있야한다.
어뎁터 설계 패턴을 사용하면, 한 클래스의 인터페이스를 클라이언트가 예상하는 인터페이스 변환할 수 있다.

쉽게 설명해봅시다.


제가 일본으로 이민을 갔는데, 일본에는 V110 볼트를 많이 사용하고 있습니다.
하지만 한국은 v220을 공통으로 사용하고 있기 때문에, 플러그가 맞지 않습니다.

이럴땐 어떻게 해야할까요?

정답은 Converter를 사용하는 것입니다.

이와 같이 Adpater는 아래와 같이 많이 사용됩니다.

  • 인터페이스가 있는 클래스를 다른 인터페이스로 변환시킬때
  • 데이터를 다른 포맷으로 변환시킬때
  • 그냥 대체적으로 안드로이드에 많이 녹아있다.

코드로 한번 설명해볼까요?

// 서드 파티 라이브러리라고 생각하자.
// 이값은 절대 변경할 수 없다.
// 이걸 List에 보여준다고 생각하자.
data class DisplayDataType(val index: Float, val data: String)

class DataDisplay {

    fun displayData(data: DisplayDataType) {
        println("대충 화면 표시")
    }

}

예를들어 기존 코드를 라이브러리를 통해 뭔가 하고싶습니다.
하지만 라이브러리의 값을 바꾸기는 뜯지 않는 이상, 불가능합니다.

//기존에 있었던 코드... 

data class DatabaseData(val position: Int, val amout: Int)


class DatabaseDataGenerator {
    fun generateData(): List<DatabaseData> {
        val list = arrayListOf<DatabaseData>()
        list.add(DatabaseData(2, 2))
        list.add(DatabaseData(3, 10))
        list.add(DatabaseData(4, 23))
        return list
    }
}

그렇다고 기존 코드를 라이브러리로 교체하기엔, 변경이 너무 많이 일어납니다.

이럴때 Adapter 패턴을 정의하여 처리할수 있습니다.

interface DatabaseDataConverter {
    fun convertData(data: List<DatabaseData>): List<DisplayDataType>
}

//기존에 있는 DataBaseData를 Library인 DisplayDataType으로 Convert하고 있다.

class DataDisplayAdapter(val display: DataDisplay) : DatabaseDataConverter {
    override fun convertData(data: List<DatabaseData>): List<DisplayDataType> {
        val returnList = arrayListOf<DisplayDataType>()
        for (datum in data) {
            val ddt = DisplayDataType(datum.position.toFloat(), datum.amout.toString())
            display.displayData(ddt)
            returnList.add(ddt)
        }
        return returnList
    }

}

Adapter 패턴을 적용함으로써, 코드를 삭제하지않고 라이브러리를 쉽게 적용할 수 있었습니다.

        val generator = DatabaseDataGenerator()
        val generatedData = generator.generateData()
        //어뎁터를 사용해서 쉽게 컨버트를 할수 있었다.
        val adapter = DataDisplayAdapter(DataDisplay())
        val convertData = adapter.convertData(generatedData)

Mapper랑 다른것인가?

저는 여기서 왜인지 Mapper와 비슷한 기능을 한다고 느껴졌었는데요.

https://stackoverflow.com/questions/42120946/is-a-mapper-a-version-of-the-adapter-pattern
에서는 어뎁터를 객체가 아닌 인터페이스 Converter라고 생각해야한다고 합니다.

// in 객체가 out 객체로 만들어지는 Mapper
// instance가 instance를 만든다.

internal fun LoginRequest.toDomain() = Login(
    loginMethod = this.loginMethod,
    uid = this.uid,
    email = this.email,
    password = password,
    userType = this.userType
)

internal fun Login.toMapper() = LoginRequest(
    loginMethod = this.loginMethod,
    uid = this.uid,
    email = this.email,
    password = password,
    userType = this.userType
)
//  새로운 인스턴스를 만드는것이 아닌, 기존에 있던 class를 적응시키는것이 목적이다.
 val adapter = DataDisplayAdapter(DataDisplay())
 val convertData = adapter.convertData(generatedData)

적혀있는 바로는 mapping보다 adpater를 사용하는것이 더 적은 비용을 들일수 있다고 합니다.


https://stackoverflow.com/questions/42120946/is-a-mapper-a-version-of-the-adapter-pattern

HeadFirst Design

Complete Kotlin Design Patterns masterclass 2022(Udemy)

profile
쉽게 가르칠수 있도록 노력하자

0개의 댓글