Class에 관하여

2024. 4. 24. 16:45TIL

✔오늘 배운 중요한 🔑 point

  • 객체지향은 기본적으로 다른 객체에 의존하지않고 자율적인 것이다. 각 개체들이 능동적이고 자율적이기 때문에 코드에 대한 이해나 코드의 변경 또한 용이해지기 때문에 객체 지향적으로 설계하는것이 매우 중요하다
  • 상속은 부모의 재산을 자식이 물려받듯이 부모 클래스의 기능들을 상속받으면서 확장 시키는 개념이라면  조합은 컴퓨터라는 클래스 안에 키보드 클래스,마우스 클래스, 모니터 클래스의 객체를 포함시켜서 기능을 추가하고 모듈화 된 형태로 만든다는 개념이다   즉 상속 ==DNA   조합 ==합체!
  • abstract키워드는 클래스나 메서드를 완전하지 않은 상태로 남겨둘때 사용하며 , open 키워드는 클래스나 메서드를 다른 클래스에서 상속하거나 확장할 때 사용된다

🎯 오늘 배운 내용

객체지향 프로그래밍이란?

♤객체 지향 프로그래밍(OOP)은 프로그램을 여러 개의 독립된 객체로 나누고, 각 객체가 데이터와 기능을 가지며 상호작용하는 방식

책임(Responsibility): 객체가 수행해야 하는 역할 또는 기능을 말합니다. 예를 들어, 자동차 객체의 주행이나 정지는 그 객체의 책임입니다.

역할(Role): 객체가 수행하는 책임의 집합을 의미합니다. 여러 객체가 동일한 역할을 수행할 수 있습니다.

상호작용(Interaction): 객체 간에 서로 메시지를 주고받아 책임을 수행하고 상호작용하는 것을 의미합니다.

☆객체 지향 프로그래밍을 잘 한다는건 책임과 역할을 잘 나누어 코드를 작성한다는 것!

 

Class & Instance

Class는 설계도, 붕어빵 틀

Instance는 붕어빵 틀로 실제 붕어빵을 만드는 것

Instance는 Class가 실체화 된 것
class Chapter3HW {
    fun printWhoYouAre(){
        println("안녕하세요!")           //이 클래스는 붕어빵 틀
    }
}

fun main(){
    var hello = Chapter3HW()   // 붕어빵 틀인 class를 Instance로 실체화시키기
    hello.printWhoYouAre()
}

 

Interface

서로 다른 class들간의 공통된 동작을 정의하기 위해서 사용된다
interface Chapter3 {
    fun homework()
}

class UserA : Chapter3 {
    override fun homework() {
        println("오늘은 강의 복습을 해볼까")
    }
}

class UserB : Chapter3 {
    override fun homework() {
        println("3주차 TIL을 작성해보자")
    }
}

fun main() {
    val userA = UserA()
    val userB = UserB()

    userA.homework()
    userA.homework()
}

 

상속

공통적인 요소들을 부모 자식간의 상속관계로서 다형성을 구현할 수 있다 
fun main(){
    var kot2=Kotlin2()
    var jav2=Java2()
    var uni1=Unity1()
    var pyt3=Python3()

    kot2.basicRule()
    jav2.basicRule()
    uni1.basicRule()
    pyt3.basicRule()

}

open class Sparta{
    fun basicRule(){
        println("출석체크 꼭 하기")
        println("TIL작성하기")
        println("하루에 강의 1개씩 수강하기")
    }
}
class Kotlin2: Sparta(){

}
class Java2: Sparta(){

}
class Unity1: Sparta(){

}
class Python3: Sparta(){

}

basicRule()의 경우 트랙에 상관없이 모두다 숙지해야하는 상황이므로 상속관계를 활용하여 다형성을 구현할 수 있다

 

조합

조합은 다른 클래스의 인스턴스를 포함하여 새로운 기능을 추가하는것이다
class Bag(
		val maxWeight: Int,
		var currentWeight: 0,
) {
		var itemList: MutableList<Item> = mutableListOf()

		fun takeItem(item: Item) {
		}
}


class Hero(bag: Bag): Character {
		...


		fun takeItem(item: Item) {
				bag.takeItem(item)
		}
}

 

생성자

class를 실체화할 때(instance화 할때) 최초로 실행할 로직
별도로 생성자를 입력하지 않으면 자동으로 주생성자가 생성된다
class Sparta {
    var name: String = ""
    var age: Int = 0
    var lectureTime: Double =0.0

    // 보조 생성자 선언하기
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }
}

fun main() {
    val sparta = Sparta("HJP", 26)
    println("Name: ${sparta.name}, Age: ${sparta.age}")
}

주요 생성자가 충분히 기능을 수행할 수 있는 경우에는 굳이 보조 생성자를 선언할 필요는 없지만 주요 생성자로서 처리할 수 없는 초기화 로직이 있는 경우에는 보조 생성자를 따로 선언해서 사용하는것이 필요하다

 

접근 제한자

public: 명시하지 않으면 기본적으로 public (어디서나 접근 가능!)
private: 동일한 클래스 내부에서만 접근 가능
internal: 같은 모듈 내부에서만 접근 가능
protected: 기본적으로 private이지만 상속을 받은경우에 타 모듈에서 접근 가능

접근권한을 통해서 코드 유지보수 하기에 용이해짐

 

Overriding

상속받은 부모 클래스의 정보나 메소드를 재설계하는 것
abstract class Calculator {
    abstract  fun operation(num1:Double,num2:Double):Double
}

class AddOperation():Calculator(){
    override fun operation(num1:Double,num2:Double):Double {
        return num1+num2
    }
}
class SubstractOperation():Calculator(){
    override fun operation(num1:Double,num2:Double):Double {
        return num1-num2
    }
}
class MultiplyOperation():Calculator(){
    override fun operation(num1:Double,num2:Double):Double {
        return num1*num2
    }
}
class DivideOperation():Calculator(){
    override fun operation(num1:Double,num2:Double):Double {
        return num1/num2
    }
}
class RemainderOperation():Calculator(){
    override fun operation(num1:Double,num2:Double):Double {
        return num1%num2
    }
}

Calculator라는 부모  class를 상속하여 operation()함수를 override하여 재설계 할 수 있다

 

Overloading

동일한 이름의 메소드를 매개변수의 갯수와 자료형을 다르게 정의하는 것
fun main(){
    hello()
    hello("안녕~")
}
fun hello(){
    println("안녕하세요~")
}
fun hello(str:String){
    println(str)
}

오버로딩을 통해 똑같은 이름의 hello 메소드가 사용가능한것을 볼 수 있다

 

data class  (데이터 묶기)

데이터를 보관하고 관리하기 위한 여러 가지 메서드를 자동으로 생성한다
주로 데이터를 담는 목적으로 사용된다

equals() : 동일한 객체인지 비교해서 true 또는 false를 반환

hashCode(): 객체를 구분하기 위한 고유값을 반환

toString(): 현재 객체의 모든 정보(프로퍼티)를 출력

copy(): 현재 객체의 모든 정보를 복사해서 새로운 객체를 반환
data class Sparta(val name: String, val age: Int, val lectureTime:Double)

 

enum class  (상수 묶기)

관련된 여러 다른 상수들을 그룹화 하는 class이다
코드의 가독성을 높이고 유지보수를 용이하게 하는 목적이 있다
enum class Date(val num: Int) {
    YEAR(365),
    MONTH(12);

    fun rotate(degrees: Int): Date {
        val newDegrees = (this.num + degrees) % 360
        return values().first { it.num == newDegrees }
    }
}

 

sealed class  (자식 클래스 미리 정의)

상속받을 수 있는 식클래스들을 미리 정의해서 무분별한 상속을 방지할 수 있다
sealed class Calculator {
    abstract fun operation(num1: Double, num2: Double): Double

    class AddOperation : Calculator() {
        override fun operation(num1: Double, num2: Double): Double {
            return num1 + num2
        }
    }
}

 

 

🤔 어떻게 활용할까?

계산기 프로그램을 만들때 더하기,빼기,곱하기 등의 공통된 연산이라는 목적을 가진 클래스들을  하나의 추상 클래스를 상속하여 오버라이딩 하는 식으로 코드를 간결하게 작성할 수 있을 것이다.

또한 data class나 enum class , override,overload 등 여러 기술들은 사용하지 않아도 프로그램이 돌아가는데 지장은 없지만 이러한 기술들을 올바르게 이해하고 사용함으로서 코드를 더욱 명확하고 효율적으로 작성할 수 있을것이다.

📓 오늘의 한줄

So we beat on, boats against the current, borne back ceaselessly into the past                                                                                        - Francis Scott Key Fitzgerald -

'TIL' 카테고리의 다른 글

여러작업을 한번에 수행하자  (0) 2024.04.26
Test Code 작성을 생활화 합시다  (0) 2024.04.25
Kotlin 기초문법  (0) 2024.04.23
Kotlin과 사용규칙  (0) 2024.04.22
미니 팀프로젝트 회고  (0) 2024.04.19