[기초편] Kotlin 제6강 - 의뢰류와 속성
위탁류
하나의 인터페이스를 실현하고by 키워드를 사용하여 인터페이스를 다른 대상에게 의뢰할 수 있습니다.
interface OnClickListener{
fun onClick()
fun onLongClick()
}
class ViewClickDelegate : OnClickListener{
override fun onClick(){
println("ViewClickDelegate onClick")
}
override fun onLongClick() {
println("ViewClickDelegate onLongClick")
}
}
class View(val name: String, onClickListener: OnClickListener) : OnClickListener by onClickListener{
override fun onLongClick() {
println("$name onLongClick")
}
}
클래스 의뢰 후에도 우리는 다시 쓰는 방식으로 의뢰 클래스의 실현을 덮어쓸 수 있습니다. 여기에서View는onLongClick 방법을 실현하고 ViewClickDelegate 클래스의onLongClick 방법을 덮어씁니다.
클래스 의뢰의 본질은 추상적인 방법의 실현을by후의 의뢰 대상에게 맡긴다는 것이다
초기화 및 위임 지연 속성
초기화 지연 속성
대상이 만들어질 때 초기화되지 않고 처음 사용할 때 초기화됩니다.완성 후 일반 속성처럼 사용
open class Food(val name: String) {
override fun toString(): String {
return "[$name]"
}
}
class Container(val name: String) {
lateinit var foodList: List
}
불활성 초기화 속성
이 속성을 처음 사용할 때 초기화되고 한 번만 초기화됩니다.초기화 여부를 기호로 표시하면 기호는 여러 가지 선택과 실현 방식이 있다.
코드 정의에서 초기화를 실행하면 코드 유지보수에 도움이 됩니다.
지령식 언어에 대해 이 모델은 위험, 특히 공유 상태를 사용하는 프로그램 습관을 잠재하고 있을 수 있다.
일반적 실현
class Container2(val name: String) {
private var _foodList: List? = null
val foodList: List
get() {
if (_foodList == null) {
_foodList = arrayListOf(Food(" "))
}
return _foodList!!
}
}
by lazy () {} 불활성 초기화
class Container4(val name: String) {
val food: Food by lazy{
Food(" ")
}
}
//
class Container5(val name: String) {
val food: Food by lazy(Container5::class){
Food(" ")
}
}
// SYNCHRONIZED
//PUBLICATION, ,
class Container6(val name: String) {
val food: Food by lazy(LazyThreadSafetyMode.SYNCHRONIZED){
Food(" ")
}
}
자바빈의 디자인에서 속성에 따라 네 가지 유형으로 나뉜다. 그것이 바로 단값 속성, 인덱스 속성이다.연관 속성, 제한 속성.Kotlin이 연관 및 제한 속성을 구현하는 방법
연관 속성(관찰 가능 속성)
PropertyChangeSupport 코드를 통한 속성 스니핑
class Shelf(val name: String, _book: Book) {
private val propertyChange: PropertyChangeSupport = PropertyChangeSupport(this)
var book: Book = _book
set(value) {
val oldBook = field
field = value
propertyChange.firePropertyChange("book", oldBook, value)
}
fun addBookChangeListener(propertyChangeListener: PropertyChangeListener) {
propertyChange.addPropertyChangeListener("book", propertyChangeListener)
}
fun removeBookChangeListener(propertyChangeListener: PropertyChangeListener) {
propertyChange.removePropertyChangeListener("book", propertyChangeListener)
}
}
논리를 봉하여 기류를 추출하다
open class BasePropertyChange {
val propertyChange = PropertyChangeSupport(this)
protected fun addChangeListener(key: String, propertyChangeListener: PropertyChangeListener) {
propertyChange.addPropertyChangeListener(key, propertyChangeListener)
}
protected fun removeChangeListener(key: String, propertyChangeListener: PropertyChangeListener) {
propertyChange.removePropertyChangeListener(key, propertyChangeListener)
}
}
class Shelf_2(val name: String, _book: Book) : BasePropertyChange() {
var book: Book = _book
set(value) {
val oldBook = field
field = value
propertyChange.firePropertyChange("book", oldBook, value)
}
fun addBookChangeListener(propertyChangeListener: PropertyChangeListener) {
addChangeListener("book", propertyChangeListener)
}
fun removeBookChangeListener(propertyChangeListener: PropertyChangeListener) {
removeChangeListener("book", propertyChangeListener)
}
}
책의 set 액세서리의 논리를 클래스로 봉합하기
class BookDelegate(_book: Book, val propertyChange: PropertyChangeSupport) {
var field: Book = _book
fun getValue(): Book = field
fun setValue(value: Book) {
val oldBook = field
field = value
propertyChange.firePropertyChange("book", oldBook, value)
}
}
class Shelf2(val name: String, _book: Book) : BasePropertyChange() {
val _bookDelegate: BookDelegate = BookDelegate(_book, propertyChange)
var book: Book
set(value) {
_bookDelegate.setValue(value)
}
get() = _bookDelegate.getValue()
fun addBookChangeListener(propertyChangeListener: PropertyChangeListener) {
addChangeListener("book", propertyChangeListener)
}
fun removeBookChangeListener(propertyChangeListener: PropertyChangeListener) {
removeChangeListener("book", propertyChangeListener)
}
}
이로써 우리는 Kotlin으로 수동으로 속성 변화를 관찰할 수 있는 기능을 실현하여 테스트하였다.
fun testObserverField() {
val shelf = Shelf2(" ", Book("Think in java"))
shelf.addBookChangeListener(object : PropertyChangeListener {
override fun propertyChange(evt: PropertyChangeEvent?) {
val oldBook = evt?.oldValue as Book
val newBook = evt.newValue as Book
println("old book = $oldBook , new book = $newBook")
}
})
shelf.book = Book("Kotlin in action")
}
위 코드 실행 결과는 다음과 같습니다.
old book = Book(name=Think in java) , new book = Book(name=Kotlin in action)
Kotlin 위임으로 구현
Kotlin의 의뢰 속성은 언어 차원에서 속성의 읽기 전용기에서 의뢰 클래스에서operator가 수식하는 두 가지 인자 getValue 방법을 호출하고 속성 쓰기 전용기에서operator가 setValue를 수식하는 세 가지 인자 방법을 호출합니다
class BookDelegate2(_book: Book, val propertyChange: PropertyChangeSupport) {
var field: Book = _book
operator fun getValue(shelf3: Shelf3, prop: KProperty): Book = field
operator fun setValue(shelf3: Shelf3, prop: KProperty, newValue: Book) {
val oldBook = field
field = newValue
propertyChange.firePropertyChange("book", oldBook, newValue)
}
}
class Shelf3(val name: String, _book: Book) : BasePropertyChange() {
var book: Book by BookDelegate2(_book, propertyChange)
fun addBookChangeListener(propertyChangeListener: PropertyChangeListener) {
addChangeListener("book", propertyChangeListener)
}
fun removeBookChangeListener(propertyChangeListener: PropertyChangeListener) {
removeChangeListener("book", propertyChangeListener)
}
}
일반적으로 ReadWriteProperty 인터페이스를 통해 의뢰를 쉽게 수행할 수 있습니다
class BookDelegate3(var field: Book, val propertyChange: PropertyChangeSupport) : ReadWriteProperty {
override fun getValue(thisRef: Shelf3_1, property: KProperty): Book {
return field
}
override fun setValue(thisRef: Shelf3_1, property: KProperty, value: Book) {
val oldBook = field
field = value
propertyChange.firePropertyChange("book", oldBook, value)
}
}
class Shelf3_1(val name: String, _book: Book) : BasePropertyChange() {
var book: Book by BookDelegate3(_book, propertyChange)
fun addBookChangeListener(propertyChangeListener: PropertyChangeListener) {
addChangeListener("book", propertyChangeListener)
}
fun removeBookChangeListener(propertyChangeListener: PropertyChangeListener) {
removeChangeListener("book", propertyChangeListener)
}
}
위 코드를 테스트합니다.
fun testDelegateFieldForKotlin() {
val shelf = Shelf3_1(" ", Book("Think in java"))
shelf.addBookChangeListener(object : PropertyChangeListener {
override fun propertyChange(evt: PropertyChangeEvent?) {
val oldBook = evt?.oldValue as Book
val newBook = evt?.newValue as Book
println("Kotlin old book is $oldBook, and new book is $newBook")
}
})
shelf.book = Book("Kotlin in action!")
}
실행 결과는 다음과 같습니다.
Kotlin은 old book is Book(name=Think in java), and new book is Book(name=Kotlin in action!) 의뢰
위탁 속성의 본질: 속성 액세서리의 실현을 by 이후의 위탁 대상에게 건네주었다
Kotlin의 자체 구현을 사용하여 관찰 가능한 속성
사실,Delegate.observable () 클래스는 위에서 언급한 모든 논리를 실현했습니다.
델게이트 한번 봅시다.observable 방법의 원본 코드
public inline fun observable(initialValue: T, crossinline onChange: (property: KProperty, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty = object : ObservableProperty(initialValue) {
override fun afterChange(property: KProperty, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
이 방법은 Observable Property 대상을 되돌려줍니다. Observable Property 대상의 원본 코드를 보십시오
public abstract class ObservableProperty(initialValue: T) : ReadWriteProperty {
private var value = initialValue
protected open fun beforeChange(property: KProperty, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange (property: KProperty, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
이 대상은 getValue와 setValue 방법이 있습니다. 이것은 우리가 실현한 BookDelegate 3류의 getValue와 setValue 방법의 논리와 거의 같습니다.다른 점은 정부측에서 beforeChange () 제어와 애프터 Change () 를 사용하여 클래스 덮어쓰기를 할 수 있다는 것이다.
Kotlin 표준 라이브러리는 속성을 관찰할 수 있는 속성 의뢰를 제공합니다
class Shelf4(val name: String, _book: Book) {
var book: Book by Delegates.observable(_book, {property, oldValue, newValue ->
println("The old book's name is \"${oldValue.name}\", and the new book's name is \"${newValue.name}\"")
})
}
상술한 코드를 테스트해 보다
fun testObserverFieldForKotlin(){
val shelf = Shelf4(" ", Book("think in java"))
shelf.book = Book("Kotlin in action")
}
실행 결과는 다음과 같습니다.
The old book's name is "think in java", and the new book's name is "Kotlin in action"
속성 제한
Kotlin 도 기존 의뢰 클래스를 제공하여 속성을 제한합니다
class Shelf5(val name: String, val book: Book ,_year: Int) {
var year: Int by Delegates.vetoable(_year, {property, oldValue, newValue ->
newValue <= 99
})
}
위 코드 테스트
fun testVetoableFieldForKotlin(){
val shelf = Shelf5(" ", Book("think in java"), 0)
shelf.year = 200
println("current book is ${shelf.year}")
shelf.year = 20
println("current book is ${shelf.year}")
}
실행 결과는 다음과 같습니다.
current book is 0 current book is 20
주의: 상기에서 사용한 것은 구성원 함수이며, 사실상 확장 함수도 위탁 속성을 실현할 수 있다
Map을 사용하여 위임 속성 구현
MapAccessors.kt 파일에는 다음과 같은 확장 함수 원본이 있습니다
@kotlin.jvm.JvmName("getVarContravariant")
@kotlin.internal.LowPriorityInOverloadResolution
@kotlin.internal.InlineOnly
public inline fun MutableMap.getValue(thisRef: Any?, property: KProperty): V
= @Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V)
@kotlin.internal.InlineOnly
public inline operator fun MutableMap.setValue(thisRef: Any?, property: KProperty, value: V) {
this.put(property.name, value)
}
이를 통해 알 수 있듯이 MutableMap에는 getValue 방법과 setValue 방법이 존재하는데 위탁에 사용할 수 있다. 사실상 그렇다.
예를 들면 다음과 같습니다.
class Fruit(name: String) : Food(name){
private val attributeMap = HashMap()
val color: String by attributeMap
val size: String by attributeMap
fun setAttributeMap(name: String, value: String){
attributeMap.put(name, value)
}
}
fun testDelegateMap(){
val fruit = Fruit(" ")
fruit.setAttributeMap("color", " ")
fruit.setAttributeMap("size", "2kg")
println("color = ${fruit.color}, size = ${fruit.size}")
}
실행 결과
color = 그린, 크기 = 2kg
소결
클래스 의뢰의 본질은 추상적인 방법의 실현을by후의 의뢰 대상에게 맡긴다는 것이다
속성 의뢰의 본질은: 속성 액세서리의 실현을 by 이후의 의뢰 대상에게 맡긴다는 것이다.
확장 함수도 속성 의뢰 실현
참고 자료
위키백과: 불활성 초기화 모드
위키백과: 불활성 값 구하기
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.