Необязательно передать параметр generi c? - PullRequest
2 голосов
/ 28 мая 2020

У меня есть следующий интерфейс NetworkUseCase, который обрабатывает сетевой запрос. P - это тип requestData, а R - тип responseData.

interface NetworkUseCase<in P, out R> {
    fun process(requestData: P) : R
}

Обычно он используется следующим образом:

class ConcreteUseCase : NetworkUseCase<ConcreteRequestData, ConcreteResponseData> {
    override fun process(requestData: ConcreteRequestData): ConcreteResponseData {
        ...
    }
}

// It is called like this
val responseData = ConcreteUseCase().process(requestData)

Однако , в некоторых случаях не требуется requestData . В этом случае аргумент requestData передаваться не должен. Но я не уверен, как этого добиться.

val responseData = ConcreteUseCase().process()

До сих пор я установил для типа requestData значение Unit, но тогда мне все равно нужно передать Unit в качестве параметра:

class ConcreteUseCase : NetworkUseCase<Unit, ConcreteResponseData> {
    override fun process(requestData: Unit): ConcreteResponseData {
        ...
    }
}

// It is called like this
val responseData = ConcreteUseCase().process(Unit)

Есть ли способ избежать принудительной передачи аргумента в process()?

Ответы [ 3 ]

3 голосов
/ 28 мая 2020

Вы можете написать функцию расширения, чтобы перегрузить ее, чтобы любая конкретная версия, использующая Unit для первого типа, автоматически имела доступ к этой более простой перегрузке:

fun <T> NetworkUseCase<Unit, T>.process() = process(Unit)

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

1 голос
/ 28 мая 2020

Кажется, вам нужен тип ввода, допускающий значение NULL, со значением по умолчанию

interface NetworkUseCase<in P, out R> {
    fun process(requestData: P? = null) : R
}

class ConcreteUseCase : NetworkUseCase<ConcreteRequestData, ConcreteResponseData> {
    override fun process(requestData: ConcreteRequestData?): ConcreteResponseData {
        //...
    }
}

Тогда вы можете просто назвать его так:

val responseData = ConcreteUseCase().process()

EDIT:

Это решение будет работать нормально, когда необходимо передать параметр функции процесса:

val resquestData: ConcreteRequestData = ...
ConcreteUseCase().process(resquestData)

Это связано с тем, что тип, не допускающий значения NULL, является подтипом его соответствующего значения NULL.

0 голосов
/ 28 мая 2020

Вы также можете определить псевдоним типа для NetworkUseCase без данных запроса:

typealias NoRequestDataNetworkUseCase<R> = NetworkUseCase<Unit, R>

и добавить функцию расширения к псевдониму типа, например @ Tenfour04 упомянуто .

fun <T> NoRequestDataNetworkUseCase<T>.process() = process(Unit)

, поэтому вы будете использовать его так:

class ConcreteUseCase : NoRequestDataNetworkUseCase<ConcreteResponseData> {
    override fun process(requestData: Unit): ConcreteResponseData {
        // ...
    }
}

// It is called like this
val responseData = ConcreteUseCase().process()

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

interface NoRequestDataNetworkUseCase<out R> {
    fun process() : R
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...