Class에 관하여
2024. 4. 24. 16:45ㆍTIL
✔오늘 배운 중요한 🔑 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 |