Предполагаемые типы, распознаваемые реализацией протокола в Котлине - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь создать систему, в которой реализации протокола (или абстрактного класса) отвечают минимальным требованиям этого протокола, но все еще имеют доступ к уникальной функциональности, которая поставляется с предоставленным решением. Позвольте мне проиллюстрировать это на примере:

interface Food
interface Animal {
    val favoriteFood: Food
}

class Banana: Food {
    fun peel() {
        print("Banana peeled")
    }
}

class Monkey: Animal {
    override val favoriteFood: Food = Banana()

    init {
        favoriteFood.peel() // Doesn't work as type is Food, not Banana
    }
}

Теперь, чтобы взломать это, я искал обобщенные и усовершенствованные функции, но я не смог придумать что-то, что работает выразительным образом.

Я должен отметить, что мои реализации должны будут выполнять более одного требования. Я мог бы заставить это работать с использованием обобщений в протоколе.

interface Animal<T: Food, B: Behaviour>

Это бы сработало, но с несколькими требованиями это быстро выглядит нелепо, и я чувствую, что что-то упустил. Обобщения в свойствах не работают, если я не пропущу что-то в следующем примере.

// Protocol
val <T> favoriteFood: <T: Food>
// Implementation (ideally, but wouldn't work like that I guess)
override val favoriteFood: Banana = Banana()

Тогда и мой ограниченный подход тоже не выглядит так:

open class Animal {
    // This should ideally be private to prevent incorrect use
    var favoriteFood: Food? = null

    fun registerFavoriteFood(food: Food) {
        favoriteFood = food
    }

    // This probably doesn't even have to be inline+reified
    inline fun <reified  T> getFavoriteFood() : T {
        // Of course we need to validate if favoriteFood matches T 
        return favoriteFood as T
    } 
}

class Monkey: Animal() {
    init {
        registerFavoriteFood(Banana())
        getFavoriteFood<Banana>().peel()
    }
}

На данный момент я не совсем уверен, не вижу ли я, как это сделать, или это невозможно. Хотя кажется, что это возможно, и мне интересно, сможет ли кто-нибудь из вас указать мне правильное направление, как решить эту проблему.

Или, может быть, даже не имеет смысла то, что я пытаюсь сделать, но даже то, что я хотел бы услышать, поскольку это имеет смысл для установки, которую я представляю.

Заранее спасибо.

Редактировать после первого ответа: Я намерен получить доступ к фавориту за пределами стадии строительства. Превратил изменчивый любимый Food в val, так как он лучше соответствует цели.

1 Ответ

0 голосов
/ 24 января 2019

Пока вы только пытаетесь получить доступ к favoriteFood во время строительства, это неплохо:

class Monkey: Animal {
    override var favoriteFood: Food? // no initializer here

    init {
        val food = Banana()
        favoriteFood = food
        food.peel()
    }
}

Если вы не ограничиваете себяк init разделам и другим операциям времени конструирования, то, что вы пытаетесь сделать, в корне нарушено.

val animal: Animal = Monkey()
animal.favoriteFood = Orange() // favoriteFood is a var, so it's publicly modifiable
animal.something() // can't assume favoriteFood is a Banana!

Вы можете превратить favoriteFood в val, что поможет.Но вы не можете сделать favoriteFood изменяемым извне типа в Food и попытаться ограничить тип favoriteFood в подтипах.

...