Swift Builder is a fast way to assign new value to the property of the object. Thanks to Hsu Li-Heng and his great article 利用 Swift 5.1 新功能實作 Fluent Interface 讓程式碼更易讀流暢!.
A fluent interface is a method for designing object-oriented APIs that relies extensively on method chaining. Its goal is to increase code legibility by creating a domain-specific language. It was coined in 2005 by Eric Evans and Martin Fowler.
A fluent interface is implemented by using method chaining to implement method cascading, concretely by having each method return self. Stated more abstractly, a fluent interface relays the instruction context of a subsequent call in method chaining, where generally the context is
- Defined through the return value of a called method
- Self-referential, where the new context is equivalent to the last context
- Terminated through the return of a void context
Note that a "fluent interface" means more than just method cascading via chaining; it entails designing an interface that reads like a Domain-specific language(DSL), using other techniques like "nested functions and object scoping"
In Swift 3.0+, returning self in the functions is one way to implement the fluent pattern.
class Person {
var firstname: String = ""
var lastname: String = ""
var favoriteQuote: String = ""
@discardableResult
func set(firstname: String) -> Self {
self.firstname = firstname
return self
}
@discardableResult
func set(lastname: String) -> Self {
self.lastname = lastname
return self
}
@discardableResult
func set(favoriteQuote: String) -> Self {
self.favoriteQuote = favoriteQuote
return self
}
}
let person = Person()
.set(firstname: "John")
.set(lastname: "Doe")
.set(favoriteQuote: "I like turtles")
By the power of Dynamic Member Lookup in Swift 4.2, and it's followed up evolve feature, Key Path Member Lookup in Swift 5.1 we can acheive Fluent Interface, by the article of Hsu Li-Heng: [利用 Swift 5.1 新功能實作 Fluent Interface 讓程式碼更易讀流暢!]. I Highly recommend reading through.
// SwiftBuilderExport.swift
@_exported import struct SwiftBuilder.Builder
struct Point {
var x:Int
var y:Int
init(x:Int = 0, y:Int = 0) {
self.x = x
self.y = y
}
}
let point = Builder(Point())
.x(1)
.y(2)
.build()
// point now have x:1 and y: 2
- Swift 5.1
The Swift Package Manager is a decentralized dependency manager for Swift.
-
Add the project to your
Package.swift
.import PackageDescription let package = Package( ... dependencies: [ ... .Package(url: "https://github.com/ytyubox/SwiftBuilder", from: "2.0.0"), ], targets: [ .target( name: "...", dependencies: ["SwiftBuilder"]) )
We can using Customize by adopt the prefix and postfix operator as follow:
import SwiftBuilder
postfix operator >|
public postfix func >| <T>(lhs: T) -> FluentInterface<T> {
return Builder(lhs)
}
postfix operator |>
public postfix func |> <T>(lhs: FluentInterface<T>) -> T {
return lhs.build()
}
Working on your first Pull Request? You can learn how from this free series, How to Contribute to an Open Source Project on GitHub.