[Kotlin] 제네릭, enum, 싱글톤, 클래스 확장

정상준·2023년 1월 20일
0

kotlin

목록 보기
23/26
post-thumbnail

📝 제네릭

제네릭은 클래스와 같은 데이터 유형이 속성 및 메서드와 함께 사용할 수 있는 알 수 없는 자리표시자 데이터 유형을 지정하도록 허용합니다.

제네릭 적용 X)

class FillInTheBlankQuestion(
    val questionText: String,
    val answer: String,
    val difficulty: String
)

class TrueOrFalseQuestion(
    val questionText: String,
    val answer: Boolean,
    val difficulty: String
)

class NumericQuestion(
    val questionText: String,
    val answer: Int,
    val difficulty: String
)

제네릭 적용 O)

class Question<T>(
    val questionText: String,
    val answer: T,
    val difficulty: String
)

✏️ 제네릭 적용 전에 매개변수 하나의 자료형이 달라 3개의 클래스를 만들어야했지만 제네릭을 사용해 해결한 것을 확인할 수 있다.

📝 enum

enum 클래스는 가능한 값 집합이 제한되어 있는 유형을 만드는 데 사용됩니다. ex) boy, girl or easy, medium, hard

enum이 필요한 경우

  • 가능한 세 가지 문자열 중 하나를 실수로 잘못 입력할 경우 버그가 발생할 수 있습니다.
  • 값이 변경되는 경우(예: "medium"의 이름이 "average"로 바뀐 경우) 문자열의 모든 사용을 업데이트해야 합니다.
  • 여러분이나 다른 개발자가 세 가지 유효한 값 중 하나가 아닌 다른 문자열을 실수로 사용하는 것을 방지하는 방법이 없습니다.
  • 난이도 수준을 더 추가하면 코드를 관리하기가 더 어려워집니다.

ex)

enum class Difficulty {
    EASY, MEDIUM, HARD
}

📝 데이터 클래스

클래스들은 대게 데이터와 메소드를 저장하는 형태로 이루어져 있습니다. 하지만 위에 보았던 Question 클래스처럼 메소드 없이 데이터로만 이루어진 클래스들도 존재합니다. 즉 작업을 실행하는 메소드가 없습니다. 이를 데이터 클래스로 정의할 수 있습니다.

클래스를 데이터 클래스로 정의하면 Kotlin 컴파일러에서 특정 가정을 하고 일부 메서드를 자동으로 구현할 수 있습니다.

  • equals()
  • hashCode(): 특정 컬렉션 유형을 사용할 때 이 메서드가 표시됩니다.
  • toString()
  • componentN(): component1(), component2() 등
  • copy()

데이터 클래스 선언)

data class Question<T>(
    val questionText: String,
    val answer: T,
    val difficulty: Difficulty
)

❗️참고: 데이터 클래스에는 생성자에 매개변수가 하나 이상 있어야 하며 모든 생성자 매개변수는 val 또는 var로 표시되어야 합니다. 데이터 클래스도 abstract 또는 open, sealed, inner일 수 없습니다.

📝 싱글톤

객체를 싱글톤으로 정의하여 객체에는 인스턴스가 하나만 있어야 함을 코드에서 명확하게 전달할 수 있습니다.
개발자가 클래스에 하나의 인스턴스만 생성되길 원하는 경우가 있습니다.

  • 현재 사용자를 대상으로 한 모바일 게임의 플레이어 통계
  • 단일 하드웨어 기기와 상호작용(예: 스피커를 통해 오디오 전송)
  • 원격 데이터 소스(예: Firebase 데이터베이스)에 액세스하는 객체
  • 한 번에 한 사용자만 로그인해야 하는 인증

ex)

object StudentProgress {
    var total: Int = 10
    var answered: Int = 3
}

그중 싱글톤을 companion으로 선언해 클래스 내부에 구현할 수 있습니다. 그렇게 하면 클래스 내부에 있는 자원들을 접근할 수 있습니다.
ex companion)

class Quiz {
    val question1 = Question<String>("Quoth the raven ___", "nevermore", Difficulty.MEDIUM)
    val question2 = Question<Boolean>("The sky is green. True or false", false, Difficulty.EASY)
    val question3 = Question<Int>("How many days are there between full moons?", 28, Difficulty.HARD)

    companion object StudentProgress {
        var total: Int = 10
        var answered: Int = 3
    }
}

❗️참고: 싱글톤 객체에는 생성자를 포함할 수 없습니다. 개발자가 인스턴스를 직접 만들 수 없기 때문입니다. 대신 모든 속성이 중괄호 안에 정의되며 초깃값이 부여됩니다.

📝 새 속성 및 메서드로 클래스 확장

Kotlin 언어의 기능을 통해 다른 개발자는 기존 데이터 유형을 확장하여 해당 데이터 유형의 일부인 것처럼 점 문법으로 액세스할 수 있는 속성과 메서드를 추가할 수 있습니다

ex)

fun main() {
    Quiz.printProgressBar()
}

// 확장 함수 추가
fun Quiz.StudentProgress.printProgressBar() {
    repeat(Quiz.answered) { print("▓") }
    repeat(Quiz.total - Quiz.answered) { print("▒") }
    println()
    println(Quiz.progressText)
}

// 확장 속성 추가
val Quiz.StudentProgress.progressText: String
    get() = "$answered of $total answered"

//싱글톤 객체(companion)
class Quiz {
    companion object StudentProgress {
        var total: Int = 10
        var answered: Int = 3
    }
}

📝 전체코드

package com.example.javapractice


fun main() {
    val question1 = Question<String>("Quoth the raven ___", "nevermore", Difficulty.MEDIUM)
    val question2 = Question<Boolean>("The sky is green. True or false", false, Difficulty.EASY)
    val question3 =
        Question<Int>("How many days are there between full moons?", 28, Difficulty.HARD)


    Quiz().apply {
        printQuiz()
    }
}


//data 클래스
data class Question<T>(
    val questionText: String,
    val answer: T,
    val difficulty: Difficulty
)

//eum 클래스
enum class Difficulty {
    EASY, MEDIUM, HARD
}

// 확장 속성 추가
val Quiz.StudentProgress.progressText: String
    get() = "$answered of $total answered"

// 확장 함수 추가
fun Quiz.StudentProgress.printProgressBar() {
    repeat(Quiz.answered) { print("▓") }
    repeat(Quiz.total - Quiz.answered) { print("▒") }
    println()
    println(Quiz.progressText)
}

//싱글톤 객체(companion)
class Quiz {
    val question1 = Question<String>("Quoth the raven ___", "nevermore", Difficulty.MEDIUM)
    val question2 = Question<Boolean>("The sky is green. True or false", false, Difficulty.EASY)
    val question3 =
        Question<Int>("How many days are there between full moons?", 28, Difficulty.HARD)

    fun printQuiz() {
        question1.let {
            println(it.questionText)
            println(it.answer)
            println(it.difficulty)
        }
        println()
        question2.let {
            println(it.questionText)
            println(it.answer)
            println(it.difficulty)
        }
        println()
        question3.let {
            println(it.questionText)
            println(it.answer)
            println(it.difficulty)
        }
        println()
    }

    companion object StudentProgress {
        var total: Int = 10
        var answered: Int = 3
    }
}

profile
안드로이드개발자

0개의 댓글