let's say we have a dynamic button that will have text and clicklistener assigned based off of our server response.
I was wondering the cleanest approach and best practice for assigning this button.
Based off of the server response, my first approach is to assign an enum to our dataclass that will be used by our view layer. This enum tells us what type of button this should be, and based off of this type, we will have a specific text and button click listener for each.
Is this approach so far good or is there a better way to start?
And what is the best way to assign the button data? Should I have maybe a Pair (or other data class?) that will store the text and click listener and have when statement that will make the assignment based off the enum?
What to you guys think is the best approach and will produce the cleanest code?
This would be in Kotlin.
CodePudding user response:
I think that the cleanest way for your case is to use polymorphism, let's say that you will have 3 types of buttons:
SumButton: will receive two numbers, sum them and return the result
MultipleButton: will receive two numbers, multiply them and return the result
DivideButton: will receive two numbers, divide them and return the result
Let's see how we can do this with polymorphism:
Create a sealed class that will hold the different button types, and when you need to add another type of button you just need to add it to the sealed class:
sealed class ButtonType(
open val buttonText: String,
open val buttonClickListener: (x: Int, y: Int) -> Int
) {
object Sum : ButtonType(
buttonText = "Sum numbers",
buttonClickListener = { x, y ->
x y
}
)
object Multiply : ButtonType(
buttonText = "Multiply numbers",
buttonClickListener = { x, y ->
x * y
}
)
object Divide : ButtonType(
buttonText ="Divide numbers",
buttonClickListener = { x, y ->
x / y
}
)
}
You can use that button type like this:
/**
* Response
*/
// Return the button type that you want depending on the response
val buttonType = ButtonType.Multiply
/**
* Fragment
*/
// Set button text
button.text = buttonType.buttonText
// Set button click listener
button.setOnClickListener {
val result = buttonType.buttonClickListener(4, 6)
Log.d("result", "$result")
}
CodePudding user response:
Here's a kind of standard approach
enum class ButtonState(@StringRes val labelResId) {
ONE(R.string.button_one_label),
TWO(R.string.button_two_label)
}
private fun updateButton(button: Button, type: ButtonState) {
// assign the label from the data -held in- the enum constant
button.text = getString(type.labelResId)
// define click listeners here and assign -depending on- the enum constant
when(type) {
ONE -> { doThing() }
TWO -> { doOtherThing() }
}.run(button::setOnClickListener)
}
so you basically have your enum with some data for each state, and then you have a function that applies a particular state to a button instance. When you need to change state, you call the function again.
But if you like, you could roll that into the enum itself:
enum class ButtonState(@StringRes val labelResId, val listener: (View) -> Unit) {
ONE(R.string.button_one_label, {
// you could write out your listener code here
}),
// or pass a reference to a function and keep your code in there
TWO(R.string.button_two_label, ::someListenerFunction);
// function that applies this enum constant's state to a button
fun applyTo(context: Context, button: Button) {
button.text = context.getString(labelResId)
button.setOnClickListener(listener)
}
}
fun someListenerFunction(view: View) {
// do stuff
}
and when you want to update your button's state
ButtonState.TWO.applyTo(context, button)
It's basically the same thing, it just depends if you prefer to have everything encapsulated in the state object, or if you want a more functional approach
The nice thing about enums too is they're Serializable
, so you can easily pass the current state around, store it in a SavedStateHandle
etc