Topic = Kotlin by 가 어떤 역할을 하는지 알아보자. ➡️ Delegate Pattern
Why
by lazy , by viewModel 등 기존에 사용해보았던 경험은 있지만 정확하게 왜 사용하는지, 어떤 이점이 있는지는 알지 못하고 있었다. by 키워드와 위임자 패턴에 대해 자세하게 알아보기로 했다.
들어가기에 앞서 by 키워드는 위임을 적용하기 위해 kotlin 에서 제공하는 키워드이다.
✅ 키워드란, 변수를 선언할 때 사용하는 val / var , 함수를 선언할 때 사용하는 fun 과 같이 프로그래밍 언어에서 특정한 기능을 수행하기 위한 말그대로의 '키워드' 이다. 키워드는 함수, 변수, 클래스의 식별자 ( ex - fun val ) 로 사용될 수 없다.
Delegate Pattern ( 위임자 패턴 )
위임, 위임자 패턴이란?
- 위임자 패턴은 기존에 자주 접하던 상속과 연관이 있다. 객체지향 프로그래밍의 상속은 한 클래스가 다른 클래스의 속성을 가져오는 행위, 동작이다. 하위 클래스, 즉 새롭게 생성된 클래스는 기존의 상위 클래스의 속성과 동작을 이어받는다. 위임( Delegate )은 단순히 다른 무엇에게 의무를 넘겨주는 것이다.
- 위임자 패턴은 어떤 기능을 자기 자신이 처리하는 것이 아닌 다른 객체에 '위임' 시켜 그 객체가 일을 처리하도록 하는 패턴으로 상속과 동일하게 코드 재사용을 할 수 있도록 하는 객체 지향 패턴 이다.
- 정리하자면 위임은 상속과 동일하게 다른 객체의 속성을 가져와 확장할 수도 있고, 상속으로 인해 생기는 불필요한 코드를 줄일 수 있는 방법이다.
위임의 특성
- 하위 클래스를 생성할 수 없다.
- 위임은 다른 클래스의 객체를 인스턴스 변수로 사용하고, 해당 인스턴스에 메세지를 전달하는 것을 의미한다. 이는 한 객체가 다른 객체에게 특정 메서드 호출을 위임하는 것으로, 클래스 간의 상속 계층이 형성되지 않는다. 이로인해 위임된 클래스는 하위 클래스를 갖을 수 없다.
- 상위 객체의 모든 메서드를 명시, 확장할 필요가 없다
- 위임을 가르키는 특정 키워드, kotlin 에서는 ' by ' 를 통해 위임 대상 객체를 가지며, 이를 통해 위임 대상 객체의 메서드를 호출할 수 있다. 메서드 호출 시 위임 대상 객체로 전달되므로, 위임 클래스에서는 상위 인스턴스의 모든 메서드를 명시적으로 확장할 필요가 없다
위임 사용하기
- 간단한 총게임 예시
- Gun 인터페이스를 구현하는 Pistol 클래스를 확장하는 2개의 클래스를 각각 상속과 위임을 통해 만들어보자
interface Gun {
fun reloading()
fun shot()
fun throwAway()
fun swap()
}
open class Pistol() : Gun {
override fun reloading() { println("재장전") }
override fun shot() { println("사격") }
override fun throwAway() { println("총 버리기") }
override fun swap() { println("총 바꾸기") }
}
// 상속
class ScopeGun : Pistol() {
override fun reloading() {
println("재장전")
}
override fun shot() {
println("사격")
}
override fun throwAway() {
println("버리기")
}
override fun swap() {
println("바꾸기")
}
fun zoom(){
println("4배율")
}
}
// 위임
class LaserPistol(base : Gun) : Gun by base {
override fun shot() { println("명중률 높은 사격") }
fun turnOnTheLaser() { println("레이저 켜기 or 끄기")}
}
fun main() {
LaserPistol(Pistol()).swap()
LaserPistol(Pistol()).turnOnTheLaser()
LaserPistol(Pistol()).shot()
LaserPistol(Pistol()).reloading()
}
- 상속을 통해 생성된 하위 클래스는 모든 메서드를 명시적으로 작성해야 하는 반면, 위임을 사용한 하위 클래스는 모든 메서드를 명시적으로 작성하지 않아 메서드 수가 많은 코드도 간결하게 코드를 작성할 수 있다.
위임사용시 주의할 점
- 상속이 비해 오버헤드가 존재
- Kotlin에서 위임은 상속과는 다른 방식으로 동작하며, 위임이 상속에 비해 오버헤드가 존재하여 실행시간이 더 길어질 수 있다.
- 상속을 사용하는 경우에는 부모 클래스의 메서드를 직접 호출할 수 있지만, 위임을 사용하는 경우에는 메서드 호출이 위임 대상 객체로 전달되는 과정이 필요하기 때문이다. 이로인해 일부 호출 지연이 발생할 수 있다.
- 위임의 오버헤드는 대부분의 상황에서는 미미하며 큰 영향을 미칠 정도는 아니라고 한다. 앱 내의 매우 빈번한 메서드 호출이 필요한 상황에서는 상속을 사용하는 것이 더 효율적일 수 있다는 점만 알고가자.
- 순환 위임 ( Curcular Delegation )
- 순환 위임이란, 순환 참조와 마찬가지로 두 개 이상의 클래스가 서로를 위임하는 상황을 말하는 것으로 무한 루프를 발생시킬 수 있어 주의하여야 한다.
- 이는 주로 상속을 허용하지 않는 클래스에 새로운 동작을 추가해야할 때 발생하는 문제이다 해당 문제는 데코레이터 패턴을 적용함으로 해결할 수 있다. → ✔️ 추후 작성 후 링크 추가 예정
결론 - 언제 상속 or 위임을 사용하면 좋을까?
상속
- 동물 상위 클래스 하위 클래스 "강아지", "다람쥐" 와 같이 클래스의 " IS - A " 관계가 적합한 경우.
- 상속 계층 구조를 형성하여 코드 구조화를 하려할 때.
- 다형성을 활용하고자 할 떄,
위임
- 위임 or 상속 하려는 객체를 향상시키고 싶지만, 더 이상 하위 분류를 하지 않아도 될 때.
- 메서드의 기능을 원하지만 메서드를 재정의하고 싶지 않을 때.
- open 되지 않은 final 클래스의 모든 메서드를 사용 및 확장하려고 할 때,
🟥 위임은 적절하게 사용한다면 유용하지만, 무분별하게 사용 시 코드 가독성도 떨어지는 문제가 생길 수 있다고 한다. 프로젝트 팀원들과 잘 상의해보고 팀 스타일에 맞춰서 적절하게 사용할 수 있도록 하면 좋을 것 같다.
[ A. 오늘 복습한 내용 / B. 다음에 학습할 내용 ]
A. lazy vs lateinit
B. 상속이 불가능한 클래스
B. inline, also, run ...등의 키워드들
[오류,에러 등등]
1. 이론 학습 위주로 특별한 오류는 없었다.
[느낀 점]
1. 캠프가 끝나고 놀고 있을 수 없어서 다시 일을 시작하고 적응 하다보니, 한동안 코드를 안보게 됐다. 덕분에 기존에 배웠던 내용들을 다 까먹었다. 꾸준히 복습해야겠다
2. 업데이트를 하고나니까 컴포즈가 기본 프로젝트 설정으로 되어있어서 당황했다.
[Reference]
'TIL' 카테고리의 다른 글
[TIL] Kotlin SharedViewModel 개념 (0) | 2023.11.21 |
---|---|
[TIL] Kotlin 단일 Activity ( Single Activity ) (0) | 2023.11.19 |
[TIL] Github Readme 작성하기 마크다운 HTML 비교 [ 기본편 ] (2) | 2023.11.14 |
[TIL] Kotlin 의존성 주입 ( Dependency Injection ) 개념편 (2) | 2023.11.13 |
[TIL] Android 이미지 포맷 형식 ( JPEG, PNG, AVIF, SVG ) (2) | 2023.11.11 |