2017-05-28 12 views
5

Jestem naprawdę zdezorientowany z powodu delegacji kotlin. Pozwólcie, że opiszę tutaj regularne podejście polimorfizmu, które wygląda tak samo jak delgacja kotlin.W jaki sposób delegacja kotlin jest przydatna?

interface Base { 
    fun print() 
} 
class BaseImpl(val x: Int) : Base { 
    override fun print() { print(x) } 
} 
fun main(args: Array<String>) { 
    val b : Base = BaseImpl(10) 
    b.print() // prints 10 
} 

mogę przekazać wszelkie wdrożone klasę Base interfejs do b zmiennej do wywołania metody obiektu określonej klasy użytkownika. Więc jaka jest korzyść z delegacji kotlin? Które jest opisane here.

interface Base { 
    fun print() 
} 
class BaseImpl(val x: Int) : Base { 
    override fun print() { print(x) } 
} 
class Derived(b: Base) : Base by b // why extra line of code? 
            // if the above example works fine without it. 
fun main(args: Array<String>) { 
    val b = BaseImpl(10) 
    Derived(b).print() // prints 10 
} 

Wiem, że jest to prosty scenariusz, w którym oba kody działają poprawnie. Powinna być korzyść z delegacji, dlatego kotlin go wprowadził. Jaka jest różnica? i w jaki sposób delegacja kotlin może być przydatna? Proszę podać przykład, który można by porównać z podejściem polimorfizmu.

+0

Zastanawiam się, czy jest to pytanie bardziej o zaletach delegacji niż o tym, jak Kotlin ją wdraża. –

+0

Zapytałem, czy wie, w jaki sposób delegacja kotlin jest przydatna? nie w jaki sposób delegacja jest przydatna. ponieważ już wiem o celu delegacji. Ale implementacja kotlina mnie dezorientuje. – UnKnown

+0

Pierwszy blok kodu nie daje wyniku równoważnego do drugiego. Spróbuj ręcznie zaimplementować 'Derived', a poczujesz różnicę. – Ilya

Odpowiedz

4

Należy również pamiętać, że nie jesteś ograniczony do tylko jednego delegata. Sposób realizacji delegacji Kotlina jest podobny do wdrożenia traits w językach takich jak Groovy. Możesz komponować różne funkcje za pośrednictwem delegatów. Sposób Kotlin można również uznać za potężniejszy, ponieważ można też "podłączyć" różne implementacje.

interface Marks { 
    fun printMarks() 
} 

class StdMarks() : Marks { 
    override fun printMarks() { println("printed marks") } 
} 

class CsvMarks() : Marks { 
    override fun printMarks() { println("printed csv marks") } 
} 

interface Totals { 
    fun printTotals() 
} 

class StdTotals : Totals { 
    override fun printTotals() { println("calculated and printed totals") } 
} 

class CheatTotals : Totals { 
    override fun printTotals() { println("calculated and printed higher totals") } 
} 

class Student(val studentId: Int, marks: Marks, totals: Totals) 
    : Marks by marks, Totals by totals 

fun main(args:Array<String>) { 
    val student = Student(1,StdMarks(), StdTotals()) 
    student.printMarks() 
    student.printTotals() 
    val cheater = Student(1,CsvMarks(), CheatTotals()) 
    cheater.printMarks() 
    cheater.printTotals() 
} 

wyjściowa:

printed marks 
calculated and printed totals 
printed csv marks 
calculated and printed higher totals 

Nie można tego zrobić z dziedziczenia.

5

Jest to przydatne ze względu na Delegation Pattern, gdzie większość zachowań może być taka sama jak cel delegacji (b), ale chcesz tylko zastąpić podzbiór metod, aby działały inaczej.

Przykładem może być implementacja InputStream, która deleguje wszystkie prace do innego InputStream, ale przesłania metodę close(), aby nie zamykać bazowego strumienia. Można to zrealizować jako:

class CloseGuardInputStream(private val base: InputStream) 
    : InputStream by base { 
    override fun close() {} 
} 
+1

czy możesz dać sprawdzony przykład? więc mogę porównać ten przykład w sposobie polimorfizmu interfejsu.Wiem, że delegacja jest przydatna, ale jak ta kotlina? – UnKnown

+0

Czy możesz wywołać powyższy kod w głównej metodzie. Czy mogę porównać do przykładu polimorfizmu interfejsu? – UnKnown

3

Jest to niezwykle przydatne do tworzenia dekoratorów i kompozycji obiektów. Joshua Bloch w Efektywnej Java, wydanie 2, pozycja 16 "Skład faworyzowania nad dziedziczeniem" pokazuje dobry przykład: dziedziczenie jest łatwe do rozbicia, a dekoratorzy nie.

Dziedziczenie:

class LoggingList<E> : ArrayList<E>() { 

    override fun add(e: E): Boolean { 
     println("added $e") 
     return super.add(e) 
    } 

    override fun addAll(e: Collection<E>): Boolean { 
     println("added all: $e") 
     return super.addAll(e) // oops! Calls [add] internally. 
    } 

} 

Delegacja:

class LoggingList<E>(delegate: MutableList<E>) : MutableList<E> by delegate { 

    override fun add(e: E): Boolean { 
     println("added $e") 
     return delegate.add(e) 
    } 

    override fun addAll(e: Collection<E>): Boolean { 
     println("added all: $e") 
     return delegate.addAll(e) // all OK 
     // it calls [delegate]'s [add] internally, not ours 
    } 

} 
+0

Nadal mogę zadzwonić wewnętrznie bez ': MutableList przez delegata' możesz dać mi działający przykład? Mogę więc porównać z podejściem polimorfizmu. – UnKnown

+0

Sądzę, że powinieneś omówić znacznie więcej na swoim przykładzie, abyś mógł zademonstrować, jak to jest "niezwykle przydatne", jak mówisz. Obawiam się, że to nie jest tak oczywiste, jak pan sugeruje. –

+1

Po pierwsze, jest to działający przykład, po prostu skopiuj i wklej go na try.kotlinlang.org i wypróbuj. Po drugie: co Miha miał na myśli to, że 'addAll' wewnętrznie wywołuje' add' na każdym nowym elemencie. więc w przykładzie dziedziczenia dostaniesz "dodane wszystko", a następnie "dodane xy" dla każdego elementu, ponieważ nadpisujemy 'add()'. w przykładzie Delegacji dostajesz tylko "dodane wszystko", ponieważ addAll nie wywołuje naszego 'add', ale raczej' add' z MutableList – D3xter

Powiązane problemy