The most notable feature of The Kotlin language is its brevity. Many of the language features in Kotlin are designed to simplify code while making it more readable. This simplicity can be maximized by implementing a DSL with the right combination of these language features.
This article describes how to construct an internal DSL for a project, using Dialog encapsulation as an example.
What is DSL?
A DSL stands for domain-specific language, which Wikipedia defines as a computer language that focuses on an application Domain.
In fact, THE SQL we are familiar with is a domain-specific language. Compared with programming languages, SQL statements are closer to spoken language, which makes SQL more expressive and readable.
Unlike regular apis, DSLS provide a special syntax structure that is intended to make the code easier to understand.
DSL:
- concise
- readable
- It has a special grammatical structure
- Applied to a specific domain
Why construct a DSL with Kotlin?
If the purpose of a DSL is to improve readability and simplify code, why Kotlin? Can’t the Java language construct DSLS?
In fact, there are many libraries in the Android space that provide dSL-like interfaces, such as Picasso:
Picasso.get()
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
Copy the code
Picasso’s interface composite DSL definition is in a sense, but given the nature of Java’s existing language, it doesn’t have much scope for constructing DSLS.
In Kotlin’s world, however, there are a number of language features that can be used to construct more concise and explicit DSLS:
- Extension function
- The default parameters
- Infix expression
- Lambda expressions
- Function parameters
- Function argument with receiver
- . .
With all that said, let’s give a practical example of how to implement a specific DSL.
DSLS simplify Dialog boilerplate code
Define a CustomDialogFragment that implements the Dialog style specified in the project and provides interfaces for setting Title, Message, LeftButton, and RightButton.
Before using a DSL
val dialogFragment = CustomDialogFragment.newInstance() dialogFragment.title = "title" dialogFragment.message = "The message" dialogFragment. RightClicks (key = "sure," dismissAfterClick = true) {toast (" clicked!" ) } val ft = supportFragmentManager.beginTransaction() val prev = supportFragmentManager.findFragmentByTag("dialog") if (prev ! = null) { ft.remove(prev) } ft.addToBackStack(null) dialogFragment.show(ft, "dialog")Copy the code
After using the DSL
showDialog { title = "title" message = "message" rightClicks { toast("clicked!" )}}Copy the code
- Omitted a lot of boilerplate code, to ensure that the code
simplicity
- Semantic clarity, with strong
readability
- The syntax structure is different from normal apis
- Dialog display applied to Android projects
How to do that?
1. Extension functions
inline fun AppCompatActivity.showDialog(settings: CustomDialogFragment.() -> Unit) : CustomDialogFragment { val dialog = CustomDialogFragment.newInstance() dialog.apply(settings) val ft = this.supportFragmentManager.beginTransaction() val prev = this.supportFragmentManager.findFragmentByTag("dialog") if (prev ! = null) { ft.remove(prev) } ft.addToBackStack(null) dialog.show(ft, "dialog") return dialog }Copy the code
AppCompatActivity adds a showDialog() extension function to the compatactivity, so you can call the showDialog() method directly in an Activity to show a Dialog.
2. Function parameters with receiver
The showDialog() method has only one parameter, Settings, of type CustomDialogFragment.() -> Unit, which is the function with the CustomDialogFragment parameter type.
Inside the showDialog() method, a CustomDialogFragment object is constructed and the dialog.apply(Settings) method is called, which sets the Dialog after the Dialog object is constructed. When the showDialog() method is actually called, you can hold the CustomDialogFragment object and then configure the Dialog by calling the public interface provided by the CustomDialogFragment.
3. Default parameters
Click: Boolean = true, callback: click (key: String = "callback ", Boolean = true) () -> Unit) { leftKey = key leftButtonDismissAfterClick = dismissAfterClick leftClicks = callback }Copy the code
In the CustomDialogFragment interface, set default values for parameters that don’t change much. Because the Kotlin language supports default parameters, you don’t need to write a lot of overloaded methods.
The source code
Github: HanderWei/android-dialog-dsl-sample
finishing
In Android projects, there are many scenarios beyond Dialog that require a lot of boilerplate code. Creating your own DSL can help simplify the development process for the entire team.
Comments are expected to point out the errors in the article.
reference
- Higher-Order Functions and Lambdas – Kotlin Programming Language
- From Java Builders to Kotlin DSLs – Kotlin Expertise Blog