왕초보 안드로이드 앱 개발 도전기

5. Kotlin 클래스(class)

joy2learn 2024. 6. 20. 11:20

객체 지향 언어에서는 클래스를 이해하는 것이 중요하다고 하는데, 처음부터 개념이 잘 이해되지는 않았습니다. 다만, 기존에 사용했던 Int, String 같은 데이터 유형도 클래스의 하나라고 하니 좀 친숙한 느낌이 들었고, codelab 의 SmartDevice 예시를 따라가면서 이해도를 높일 수 있었습니다.

 

 

1. 개요

 

클래스(class)는 객체 지향 프로그래밍(Object-Oriented Programming, OOP)의 중요한 개념으로 객체를 생성하기 위한 정보를 담고 있는 청사진입니다. Object 와 Class instance 는 구분없이 사용되는데, 객체로 번역되며, 특정 정보를 담고 있는 개별 데이터라고 보면 될 것 같습니다.

 

클래스(class) 는 다음의 세가지로 구성됩니다.

  • 속성(Properties): 객체의 속성을 지정하는 변수
  • 매서드(Methods): 클래스의 동작과 작업이 정의된 함수
  • 생성자(Constructors): 객체를 생성하는 특별한 함수

 

2. 클래스(class) 정의

    class ClassName {

    body

    }

 

ClassName은 PascalCase(첫글자가 대문자인 camelCase) 로 작성되어야 합니다. 예를 들어 SmartDevice 처럼 명명합니다.

 

2.1 클래스 매서드(method) 정의 

일반적인 함수를 정의하는 방법과 동일합니다. 클래스 본문 내에서 정의된 함수를 매서드(method) 라고 부릅니다.

 

2.2 클래스 속성 (properties) 정의

일반적인 변수를 정의하는 방법과 동일합니다. 다만, 상속관계가 있거나 게터/세터를 정의하는 경우는 추가 고려사항이 있습니다. 

아래의 코드에서는 SmartDevice 라는 클래스(class)에 devideType 이라는 속성(property)을 "unknown"으로 정의했고, 서브클래스(subclass)인 SmartTVDevice 에서 그 값을 "Smart TV"로 재정의하였습니다.

open 이나 override에 대해서는 아래 4번의 설명을 참고해주세요.

open class SmartDevice(val name: String, val category: String) {

    open val deviceType = "unknown"
class SmartTvDevice(deviceName: String, deviceCategory: String) :
    SmartDevice(name = deviceName, category = deviceCategory) {

    override val deviceType = "Smart TV"

 

2.3 게터(getter) 와 세터(setter)

클래스에서 속성을 정의할 때에는 기본적으로 자동적으로 getter와 setter 가 설정되기 때문에 별도의 처리 없이도 속성값을 조회하거나(getter) 설정할(setter) 수 있습니다. 즉, 아래의 코드에서처럼 별도로 신경쓰지 않아도 mySmartTV.volume 을 조회할 수 있고, mySmartTV.volume = 10 으로 직접 설정할 수 있습니다.

class SmartTV(val name: String) {
    var volume: Int = 5
    var brightness: Int = 50
}

fun main() {
    val mySmartTV: SmartTV = SmartTV("Samsung TV")
    println("${mySmartTV.name} current volume = ${mySmartTV.volume}")
   
    mySmartTV.volume = 10
    println("${mySmartTV.name} current volume = ${mySmartTV.volume}")
}

 

그런데, TV volume 에는 최소값과 최대값이 응당 있어야만 하는 것처럼 속성의 값에 어떤 조건을 부여해야 하는 경우가 있고, 이럴 때에는 getter 와 setter 를 직접 정의하여야 합니다. 사용자가 지정하지 않는 경우 Kotlin의 complier 는 아래와 같이 직접 작성한 보라색 문장 아래 부분에 노란색의 getter, setter 를 자동으로 생성한다고 합니다. 

    var volume: Int =5

        get() = field

        set(value) {

            field = value

        }

이를 응용하면 volume 범위를 0 에서 100까지로 지정할 수 있습니다. getter 는 자동 생성되는 부분에서 수정할 부분이 없기 때문에 추가하지 않았습니다.

    var volume: Int =5

        set(value) {

            if (value in 0..100) {field = value}

        }

 

2.4 클래스 생성자(constructor) 정의

생성자는 클래스의 오브젝트가 어떻게 생성되어야 하는지 특정하는 것이 목적입니다. 주생성자(primary constructor)와 보조생성자(secondary constructor)로 나눌 수 있는데, 보조생성자를 두는 이유는 오브젝트 생성의 유연성을 부여하기 위함입니다.

문법은 아래와 같은데, 첫 번째 줄의 파란색 부분은 constructor 라는 표현이 생략되어 있으나, 주생성자를 의미합니다. 두 번째 줄은 보조생성자를 정의하고 있으며 노란색의 매개변수들은 주생성자의 매개변수를 포함하여야 합니다. this 뒷 부분에서 주생성자의 매개변수를 나열하여 주생성자와 연결하고 있습니다.

    class ClassName(parameters) {

        constructor(parameters) : this(primary conductor parameters) {

            body

        }

    }

 

3. class instance(객체) 정의

    val objectName = ClassName()

변경가능한 변수를 만들기 위해서는 val 대신 var 를 사용합니다.

 

3.1 객체에서 매서드(method) 호출

    classObject.methodName([optional]Arguments)

 

3.2 객체의 속성(property) 호출

    classObject.propertyName

fun main() {
    var smartDevice: SmartDevice = SmartTvDevice("Android TV", "Entertainment")
    println("${smartDevice.deviceType}")
   

예를 들어, 만들어진 smartDevice 라는 객체에 대해서 smartDevice.deviceType 형태로 객체의 속성을 호출할 수 있습니다. 

 

4. 클래스(class)간의 관계: 상속(inheritance)

스마트TV 나 스마트전등 등은 스마트기기의 일부이며, 따라서 전원을 켜거나 끄는 등의 스마트기기 매서드를 재사용할 수 있을 것입니다. 이처럼 SmartDevice 클래스에 SmartTVDevice와 SmartLightDevice 클래스가 하위로 설정되어 기능을 재사용하거나 확장할 때 전자를 수퍼클래스(superclass) 혹은 부모클래스라고 부르고 후자를 서브클래스(subclass) 혹은 자식클래스라고 합니다. 

상속관계를 설정하기 위하여 아래와 같이 수퍼클래스에는 open 키워드를 추가하여 확장가능하도록 하고, 서브클래스는 선언시 콜론(:) 뒤에 수퍼플래스를 명시합니다.

또한, 경우에 따라서는 수퍼클래스에서 정의된 매서드를 서브클래스에서 일부 보완하여 재정의해야 할 수 있습니다. 이 경우 수퍼클래스의 매서드 앞에는 open 을 서브클래스의 매서드앞에는 override 를 붙여줍니다.

open class SmartDevice(val name: String, val category: String) {
    open fun turnOff() {
        deviceStatus = "off"
    }
class SmartTvDevice(deviceName: String, deviceCategory: String) :
    SmartDevice(name = deviceName, category = deviceCategory) {

    override fun turnOff() {
        super.turnOff()
        println("$name turned off")
    }

 

5. Visibility modifiers(공개상태 수정자)

캡슐화(Encapsulation)와 관련된 개념으로 class 나 package 바깥에서 승인안된 접근을 통제함으로서 데이터 보호와 코드의 유지보수성을 향상시킵니다. default 값은 public 입니다.

modifier 같은 class 내 접근 subclass 에서 접근 같은 module 내 접근 module 바깥에서 접근
private O X X X
protected O O X X
internal O O O X
public O O O O