TIL

[TIL] Kotlin delegate Pattern 위임자 패턴 ( by lazy, by remember ... )

정상호소인 2024. 1. 26. 07:01

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]

 

Delegation | Kotlin

 

kotlinlang.org

 

Delegation pattern - Wikipedia

From Wikipedia, the free encyclopedia Design pattern in object-oriented programming In software engineering, the delegation pattern is an object-oriented design pattern that allows object composition to achieve the same code reuse as inheritance. In delega

en.wikipedia.org

 

Delegation vs Inheritance in Java - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

[부스트코스/코틀린/객체지향편] 1. 객체지향의 기본(1)

클래스와 객체의 정의 객체지향 : 절차 중심의 코드를 구조적으로 하고자 함 구조적인 코드 구조를 클래스 / 객체를 이용하여 실제 세계와 비슷하게 작성 객체와 그 관계를 표현하여 확장 - 재사

jehunseo.tistory.com

 

[Kotlin][Delegation] 1. Class Delegation

코틀린에서 많이 사용하는 by 키워드, 특히나 뷰모델을 사용할 때 많이 봤었습니다. val viewModel: MainViewModel by viewModels()단순히 viewModel을 위임하는 것이라고 알고 있었는데, 위임한다는 것이 무슨

velog.io