Reputation: 969
I have the following NetworkUseCase
interface which processes a network request. P
is the type of requestData
and R
the type of responseData
.
interface NetworkUseCase<in P, out R> {
fun process(requestData: P) : R
}
The way it is normally used is the following:
class ConcreteUseCase : NetworkUseCase<ConcreteRequestData, ConcreteResponseData> {
override fun process(requestData: ConcreteRequestData): ConcreteResponseData {
...
}
}
// It is called like this
val responseData = ConcreteUseCase().process(requestData)
However, there are some use cases where there are no requestData needed. In that case, there should be no requestData argument passed. But I am not sure how to achieve that.
val responseData = ConcreteUseCase().process()
What I have done so far is to set the type of requestData to Unit but then I still need to pass Unit as a parameter:
class ConcreteUseCase : NetworkUseCase<Unit, ConcreteResponseData> {
override fun process(requestData: Unit): ConcreteResponseData {
...
}
}
// It is called like this
val responseData = ConcreteUseCase().process(Unit)
Is there a way to achieve not being forced to always pass an argument in process()
?
Upvotes: 2
Views: 92
Reputation: 2113
Seems that you need a nullable input type with a default value
interface NetworkUseCase<in P, out R> {
fun process(requestData: P? = null) : R
}
class ConcreteUseCase : NetworkUseCase<ConcreteRequestData, ConcreteResponseData> {
override fun process(requestData: ConcreteRequestData?): ConcreteResponseData {
//...
}
}
Then you can just call it like that:
val responseData = ConcreteUseCase().process()
EDIT:
This solution is gonna work just fine when it is necessary to pass a parameter to the process function:
val resquestData: ConcreteRequestData = ...
ConcreteUseCase().process(resquestData)
It is due to the fact that a non-nullable type is a subtype of its correposding nullable one.
EDIT 2:
Revisiting this answer I realized that the concrete use case may always have no parameter expected. The interface still works and the concrete class should be like that:
class ConcreteUseCase : NetworkUseCase<Unit, ConcreteResponseData> {
override fun process(requestData: Unit?): ConcreteResponseData {
//...
}
}
Upvotes: 1
Reputation: 317
You could also define a type alias for a NetworkUseCase
without request data:
typealias NoRequestDataNetworkUseCase<R> = NetworkUseCase<Unit, R>
and add an extension function to the type alias like @Tenfour04 mentioned.
fun <T> NoRequestDataNetworkUseCase<T>.process() = process(Unit)
so you will use it like this:
class ConcreteUseCase : NoRequestDataNetworkUseCase<ConcreteResponseData> {
override fun process(requestData: Unit): ConcreteResponseData {
// ...
}
}
// It is called like this
val responseData = ConcreteUseCase().process()
But I also think is better to define a different abstraction for network use cases that doesn't need request data.
interface NoRequestDataNetworkUseCase<out R> {
fun process() : R
}
Upvotes: 0
Reputation: 93834
You could write an extension function to overload it so any concrete version that uses Unit
for the first type would automatically have access to this simpler overload:
fun <T> NetworkUseCase<Unit, T>.process() = process(Unit)
But if the number of arguments for the function are not always the same, why put this function in an interface at all? You wouldn't be able to use it in an abstract way.
Upvotes: 3