객체지향프로그래밍

JENNA·2023년 12월 4일
0

클래스와 설계
: 그룹화할 수 있는 함수와 변수를 한 곳에 모아 놓고 사용하기 쉽게 이름 붙인 것

클래스의 기본 구조

  • kotlin에서 사용되는 클래스의 기본 구조
class 클래스명 {
    var 변수
    fun 함수() {
        // 코드
    }
}
  • String(문자열 저장) 클래스 코드

-length변수로 문자열 길이 알 수 있고
-plus 함수로 문자열을 이어붙일 수 있음
-compareTo는 문자열을 비교하는 기능 제공

class String{
    var length: Int
    fun plus(other: Any){
        // code
    }
    fun compareTo(other: String){
        // code
    }
}

클래스 코드 작성

  • 클래스 만들기위해 먼저 "class 이름" 정하기
  • 클래스 이름 다음에는 범위를 지정하는 중괄호 {}있어야 함
  • 중괄호{}를 스코프(scope)라고 함, 클래스에서는 "클래스 스코프"라고 함
  • 부분의 코드는 클래스 스코프 안에 작성됨
class 클래스이름 {
    // 클래스 스코프 (class scope)
}

생성자

  • 작성된 클래스를 사용 위해서 '생성자'라고 불리는 함수가 호출되어야 함
  • kotlin은 프라이머리(primary)&세컨더리(secondary)2개의 생성자 제공

*프라이머리 생성자(primary constructor)

class Person 프라이머리 생성자() {
}
  • 클래스의 헤더처럼 사용할 수 o, 조건에 따라 생략 o
  • 프라이머리 생성자도 함수이기 때문에 파라미터 사용 o
class Person constructor(value: String){
    // code
}
  • 생성자에 접근 제한자나 다른 옵션이 없다면 constructor 키워드 생략 o
class Person(value: String){
    // code
}
  • 프라이머리 생성자는 마치 헤더처럼 class키워드와 같은 위치에서 작성
  • 클래스의 생성자가 호출 -> init블록의 코드 실행 -> init블록에서는 생성자를 통해 넘어온 파라미터에 접근 o
class Person(value: String){
    init{
        Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")
    }
}
  • init 초기화 작업 필요x 라면 init 블록 작성하지 않아도 됨
  • 대신 파라미터로 전달된 값을 사용하기 위해 : 파라미터 앞에 변수 키워드 val을 붙여주면 클래스 스코프 전체에서 해당 파라미터를 사용할 수 있음
class Person(val value: String) {
    fun process() {
        print(value)
    }
}
  • 생성자 파라미터 앞에 var도 사용할 수 있지만, 읽기 전용인 val을 사용하는 것을 권장

*세컨더리 생성자(secondary constructor)

  • 세컨더리 생성자는 constructor키워드를 마치 함수처럼 클래스 스코프 안에 작성 o

ex) init블록을 작성하지 않고 constructor 다음에 괄호를 붙여서 코드 작성 o

class Person {
    constructor (value: string) {
        Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")
    }
}
  • 세컨더리 생성자는 파라미터의 개수 or 타입이 다르다면 여러 개를 중복해서 만들 수 o
class Kotlin {
    constructor (value: String){
        Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")        
    }
    constructor (value: Int){
        Log.d("class", "생성자로부터 전달받은 값은 ${value}입니다.")        
    }
    constructor (value1: Int, value2: String){
        Log.d("class", "생성자로부터 전달받은 값은 ${value1}, ${value2}입니다.")        
    }
}

*디폴트 생성자(Default constructor)

: 생성자 작성하지 않는 경우 파라미터가 없는 프라이머리 생성자가 하나 있는 것과 동일

class Student { // 생성자를 작성하지 않아도 기본 생성자가 동작합니다.
    init {
        // 기본 생성자가 없더라도 초기화가 필요하면 여기에 코드를 작성합니다.
    }
}

클래스의 사용
:클래스의 이름에 괄호를 붙여 클래스의 생성자를 호출
(constructor 키워드를 호출하지는 x)

클래스명()
  • 아무런 파라미터 없이 클래스명에 괄호 -> 생성자가 호출되면서 init블록 안의 코드가 자동 실행
  • 세컨더리 생성자의 경우 init블록이 먼저 실행 -> constructor 블록 안의 코드 그 다음 실행

ex) kotlin클래스의 생성자를 호출한 후 생성되는 것= 인스턴스(instance)라고 하는데, 생성된 인스턴스는 변수에 담아둘 수 있음

var kotlin = Kotlin()

=> 붕어빵틀 = 클래스
=> 붕어빵 = 인스턴스

  • 생성자에 파라미터 있으면 값을 입력해서 호출해야 함
var one = Person("value")
// 또는
var two = Person(1004)
  • 프로퍼티(property)와 메서드(method)
  • 클래스 내부에 정의되는 변수&함수 = 멤버변수(property), 멤버함수(method)

= 클래스의 변수 > 멤버 함수 > ----------프로퍼티(property)
= 클래스의 함수 > 멤버 함수 > ----------메서드 (method)

-> 클래스 안에 정의된 변수 = 프로퍼티(property)
-> 함수 안에 정의된 변수 = 변수 (지역변수)

class 클래스명 {
    var 변수A    // 프로퍼티: 함수 밖에 있어야 합니다.
    fun 함수(){
        var 변수B    // 변수(또는 지역변수): 함수 안에 있어야 합니다.
    }
}

ex) 프로퍼티와 메서드를 사용 위해 다음과 같이 프로퍼티 1개와 메서드 1개를 갖는 클래스를 만듦

class Pig {
    var name: String = "Pinky"
    fun printName(){
        Log.d("class", "Pig의 이름은 ${name}입니다.")
    }
}

-위에서 정의한 class를 생성자로 다음과 같이 인스턴스화해서 변수에 담기

var pig = pig()

-인스턴스가 담긴 변수명 다음에 도트 연산자(.)를 붙여서 프로퍼티와 메서드 사용

pig.name = "Pooh"
pig.printName()

/** 실행결과
Pig의 이름은 Pooh입니다.
*/

클래스 안에 정의된 함수와 변수 사용하기

  • 클래스를 사용한다 = 클래스 내부에 정의된 변수와 함수를 사용한다
  • 생성자를 통해 변수에 저장된 클래스의 인스턴스는 내부에 정의된 변수와 함수를 도트 연산자(.)로 접근할 수 있음

오브젝트
: 클래스 생성자로 인스턴스화 하지 않아도 블록 안의 프로퍼티와 메소드를 호출해서 사용 o

-object는 클래스와 다르게 앱 전체에 1개만 생성
-클래스명 그대로 사용하기 때문에 호출하는 클래스명의 첫 글자는 대문자

object Pig{
    var name: String = "Pinky"
    fun printName() {
        Log.d("class", "Pig의 이름은 ${name}입니다.")
    }
}

-object 코드 블록 안의 프로퍼티와 메소드는 클래스명에 도트 연산자를 붙여서 생성자 없이 직접 호출 o

Pig.name = "Mikey"
Pig.printName()

컴패니언 오브젝터 (companion object)

-일반 클래스에 object 기능을 추가하기 위해서 사용
-위에서 작성한 Pig코드를 다음과 같이 companion object블록으로 감싸주면 생성 과정 없이 오브젝트처럼 사용 o

class Pig {
    companion object {
        var name: String = "None"
        fun printName(){
            Log.d("class", "Pig의 이름은 ${name}입니다.")
        }
    }
    fun walk() {
        Log.d("class", "Pig가 걸어갑니다.")
    }
}

-위의 Pig는 class로 선언했기 때문에 일반 함수인 walk()는 생성자인 Pig()를 호출한 다음 변수에 저장한 후 사용 o

// companion object 안의 코드 사용하기
Pig.name = "Linda"
Pig.printName()    // Pig의 이름은 Linda입니다.
// companion object 밖의 코드 사용하기
val cutePig = Pig()
cutePig.walk()    // Pig가 걸어갑니다.

-Log 클래스의 메소드 d(), e() 모두 object 코드 블록 안에 만들어져 있기 때문에 생성자 없이 바로 호출해서 사용 o

데이터 클래스 (data class)
:간단한 값이 저장 용도로 data class 제공

data class 클래스명(val 파라미터1: 타입, var 파라미터2: 타입)
  • 데이터 클래스를 정의할 때 class 앞에 data 키워드를 사용해야 하고, 생성자 파라미터 앞에 입력하는 var(val) 키워드는 생략 불가능)

  • 생성하는 코드는 일반 클래스와 동일하게 작성

// 정의 - 주로 코드 블록(클래스 스코프)을 사용하지 않고 간단하게 작성합니다.
data class UserData(val name: String, var age: Int)
// 생성 - 일반 class의 생성자 함수를 호출하는 것과 동일합니다.
var userData = UserData("Michael", 21)

// name은 val로 선언되었기 때문에 변경 불가능합니다.
userData.name = "Sindy" // (X)
// age는 var로 선언되었기 때문에 변경 가능합니다.
userData.age = 18 // (O)
  • 일반 변수선언처럼 데이터 클래스의 파라미터를 val로 정의하면 읽기 전용

toString()메서드와 copy()메서드

-일반 클래스에서 toString()메서드를 호출하면 인스턴스의 '주소 값'을 반환하지만, 데이터 클래스는 '값'을 반환. 실제 값 모니터링할 때 좋음

Log.d("DataClass", "DataUser는 ${dataUser.toString()}")
// DataUser는 DataUser(name=Michael, age=21)
  • copy()메서드로 간단하게 값 복사 o
var newData = dataUser.copy()

일반 클래스처럼 사용하기
-일반 클래스와 동일하게 생성자 호출 -> init 블록 동작, 메서드도 사용 o

data class UserData(var name: String, var age: Int){
    init{
        Log.d("UserData", "initialized")
    }
    fun process(){
        // 클래스와 동일하게 메서드 사용이 가능합니다.
    }
} // 클래스가 생성되면 "initialized"가 출력됩니다.
  • 데이터 클래스란? 클래스와 사용법 동일하지만 주로 네트워크를 통해 데이터 주고받거나, 로컬 앱의 데이터베이스에서 데이터를 다루기 위한 용도로 사용하는 것



// 메소드 설계

// 특정한 로직을 가지는 소스코드에 별명(이름)을 붙일 수 있어요
// 이름이 붙은 로직은 앞으로 메소드라고 부를 수 있어요
// 코틀린의 메소드 기본 구조

fun 메소드이름(변수명:자료형, 변수명:자료형 ....) : 반환자료형 {
소스코드 로직
}

//ex)
// 두 개의 숫자를 더하는 메소드를 만들고, 전달하는 숫자에 따라 덧셈결과를 알려줘요
// sum메소드는 매개변수로 num1과 num2를 요구해요
// 필수로 매개변수를 넣어줘야 호출할 수 있어요

fun main() {
    var num1 = readLine()!!.toInt()
    var num2 = readLine()!!.toInt()

    // sum이라는 이름의 메소드를 호출!
    sum(num1, num2)
}

fun sum(num1:Int, num2:Int) {
    var result = num1 + num2
    println("num1과 num2의 덧셈결과는 ${result}입니다.")
}
  • ex)
    //오늘의 정보를 알려주는 메소드를 만들어요
    //반환자료형이 없을때는 Unit으로 명시하거나 생략할 수 있어요
fun main() {
    // displayInfo라는 이름의 메소드를 호출!
    displayInfo()
}

fun displayInfo() : Unit {
    println("오늘의 날씨는 화창합니다")
    println("오늘은 검정색을 조심하세요")
}
  • ex)
    //수학점수를 입력받아 등급을 출력해주는 프로그램을 학생들에게 전달했어요
    //checkRank메소드는 매개변수로 score를 요구해요
fun main() {
    var myMathScore = readLine()!!.toInt()
    
    var myRank = checkRank(myMathScore)
    println("나의 등급은 : ${myRank}")
}

fun checkRank(score:Int) : String {
		return when(score) {
			in 90..100 ->	return "A"
			in 80..89 -> return "B"
			in 70..79 -> return "C"
			else -> return "D"
		}
}
  • ex) Kotlin 컨벤션을 따르지 않은 형태
if(score >= 90) {
        return "A"
    } else if(score >= 80) {
        return "B"
    } else if(score >= 70) {
        return "C"
    } else {
        return "D"
    }
}
  • 클래스 (붕어빵 틀)

-속성 properties : var, val 같은 걸로 설정

-메소드 methods : 함수가 들어갈 수 있겠지

-생성자 constructor :
: 주생성자 (초기화코드)
: 부생성자 constructor를 통해서 오버로딩

  • 객체 instance (붕어빵)

0개의 댓글