Wzorzec delegataW wszyscy znamy i lubimy, choć często mylimy z przekierowaniemW. Często też mieszamy ten wzorzec z dekoratoremW tworząc konstrukcje, gdzie kontroler przekierowuje dane wejściowe, do jakiegoś serwisu, który to serwis jest dekoratorem do jakiejś usługi (takie samo API), którą wywołuje np. wcześniej, dokonując walidacji. Zazwyczaj sama delegacja produkuje nam masę niepotrzebnego kodu. Szczególnie jak chcemy dodać kod tylko do części metod. Twory w rodzaju:

Listing 1. Przykład z „częściową” implementacją

public class SomeService implements IService{

    @Inject
    private IService other;

    public void someExtraLogicGoesHere(){
       validate();
       other.someExtraLogicGoesHere();
    }

    public void callMe(){
        other.callMe();
    }
}

Mają to do siebie, że część kodu można by spokojnie usunąć. Jednak nie do końca można, ponieważ Java wymusza na nas implementację „wszystko albo nic” – implementujesz cały interfejs, albo nie implementujesz go wcale lub stajesz się abstrakcyjny. Kotlin udostępnia ciekawy mechanizm, oparty o generowanie kodu w czasie kompilacji. Przeanalizujmy poniższy programik:

Listing 2. Delegacja na poziomie języka w Kotlinie

interface IService {

    fun someExtraLogicGoesHere(): Unit
    fun callMe(): Unit
}

class Other : IService {

    override fun someExtraLogicGoesHere() {
        println("Thank you for add me some logic!")
    }

    override fun callMe() {
        println("Hello")
    }

}

class SomeService(val other: IService) : IService by other{

    override fun someExtraLogicGoesHere() {
        println("Extra logic")
        other.someExtraLogicGoesHere()
    }

}

fun main(args: Array<String>) {
    val o = Other()
    val s = SomeService(o)

    s.someExtraLogicGoesHere()
    s.callMe()
}

Mamy tu interfejs IService oraz dwie implementacje Other, która ma zaimplementowane wszystkie metody oraz SomeService, która implementuje tylko jedną z metod. Implementacja drugiej polega na delegacji do obiektu other. Jednak, zamiast pisać kod tak jak na listingu 1. używamy słowa kluczowego by przy definiowaniu klasy. Oczywiście, jeżeli implementujemy wiele interfejsów, możemy dla każdego z nich wskazać cel delegacji.

Podsumowanie

Mechanizm delegacji jest bardzo ciekawie rozwiązany. Będzie on przydatny tam, gdzie mamy gotowe 90% rozwiązania, zmiany chcemy wprowadzić punktowo, a nie chcemy pisać dużej ilości zbędnego kodu. Istnieje też możliwość delegowania pól. O tym następnym razem