Applying Builder Pattern for Sign in process (User-Password, Facebook, Google)

In this post I will be talking about how to create a builder that conforms the sign in foundations for User-Password, Facebook, Google process.

Tony Trejo
4 min readNov 13, 2020

What is a builder pattern?

The builder pattern is a design pattern (creational pattern) that allows us to create complex objects using sequence of actions.

With that being said let’s code an example.

The example

The goal of this example will be create a generic sign in instance that allows us to create different types of Sign in process, those are listed below:

  • UserSignIn

This sign in contains username, password and session properties.

  • FacebookSignIn

This sign in contains Facebook token and api key properties.

  • GoogleSignIn

This sign in contains Google token, api key and host properties.

First we need to define a protocol that contains all the properties used in the builder.

protocol SignInDataSource {  var email: String? { get }  var password: String? { get }  var facebookToken: String? { get }  var googleToken: String? { get }}

We need to create a provider class that conforms the SignInDataSource protocol.

final class SignInProvider<T: SignIn>: SignInDataSource {  private var elementType: SignInBuilderDataSource.Type  fileprivate(set) var email: String?  fileprivate(set) var password: String?  fileprivate(set) var facebookToken: String?  fileprivate(set) var googleToken: String?  var instance: T?  init() {  }}

Also any class used in the Builder needs to conform the SignInBuilderDataSource protocol.

// MARK: - SignInBuilderDataSource Protocol/// Protocol that all generic SignInBuilder class should implement.protocol SignInBuilderDataSource {  init()}

Now let’s create the builder class.

// MARK: - Sign in Builder/// Builder class used to simplify object creation.final class SignInBuilder<T: SignInBuilderDataSource> {  private var innerBuild = SignInProvider<T>()
init() { }
/// Setter for setting email. /// - Parameters: /// - email: Email. /// - Returns: A `SignInBuilder` @discardableResult func setEmail(_ email: String) -> SignInBuilder { innerBuild.email = email return self }
/// Setter for setting password. /// - Parameters: /// - password: Password. /// - Returns: A `SignInBuilder` @discardableResult func setPassword(_ password: String) -> SignInBuilder { innerBuild.password = password return self }
/// Setter for setting Facebook token. /// - Parameters: /// - facebookToken: Facebook token. /// - Returns: A `SignInBuilder` @discardableResult func setFacebookToken(_ facebookToken: String) -> SignInBuilder { innerBuild.facebookToken = facebookToken return self }
/// Setter for setting Google token. /// - Parameters: /// - googleToken: Google token. /// - Returns: A `SignInBuilder` @discardableResult func setGoogleToken(_ googleToken: String) -> SignInBuilder { innerBuild.googleToken = googleToken return self }
/// Build the instance. /// - Returns: A `SignInProvider<T>` func build() -> SignInProvider<T> { return innerBuild }}

Now that we have the builder done, we can instantiate different cases and validate if they are working properly.

Note: @discardableResult use to suppress the “Result unused” warning.

UserSignIn class

The idea of this class is provides the common credentials used in a sign in process.

First create a class with that name and conforms SignInBuilderDataSource then use that class in the builder.

Apply the necessary methods to set those values and finally call the build method.

final class UserSignIn: SignInBuilderDataSource {  let session = URLSession.shared  required init() {}}
let
userSignIn = SignInBuilder<UserSignIn>()
.setEmail("test@host.com") .setPassword("test123") .build()print(userSignIn.email) // test@host.comprint(userSignIn.password) // test123print(userSignIn.instance?.session) // Shared sessionprint(userSignIn.facebookToken) // nilprint(userSignIn.googleToken) // nil

You can see that facebookToken and googleToken are nil because those are not necessary in this process.

FacebookSignIn class

The idea of this class is provides the token and the api key used in the Facebook sign in process.

First create a class with that name and conforms SignInBuilderDataSource then use that class in the builder.

Apply the necessary methods to set those values and finally call the build method.

final class FacebookSignIn: SignInBuilderDataSource {  let apiKey = "some api key"  required init() { }}
let facebookSignIn = SignInBuilder<FacebookSignIn>() .setFacebookToken("2318120938jnjnkjnkda123") .build()print(facebookSignIn.facebookToken) // 2318120938jnjnkjnkda123print(facebookSignIn.instance?.apiKey) // some api keyprint(facebookSignIn.email) // nilprint(facebookSignIn.password) // nilprint(facebookSignIn.googleToken) // nil

You can see that email, password and googleToken are nil because those are not necessary in this process.

GoogleSignIn class

The idea of this class is provides the google token, api key and host properties used in the GoogleSignIn sign in process.

First create a class with that name and conforms SignInBuilderDataSource then use that class in the builder.

Apply the necessary methods to set those values and finally call the build method.

final class GoogleSignIn: SignInBuilderDataSource {  let apiKey = "some api key"  let host = "https://google.com"

required init() { }
}
let
googleSignIn = SignInBuilder<GoogleSignIn>()
.setGoogleToken("2318120938jnjnkjnkda1231qdas") .build()print(googleSignIn.googleToken) // 2318120938jnjnkjnkda1231qdasprint(googleSignIn.instance?.apiKey) // some api keyprint(googleSignIn.instance?.host) // https://google.comprint(googleSignIn.email) // nilprint(googleSignIn.password) // nilprint(googleSignIn.facebookToken) // nil

You can see that email, password and facebookToken are nil because those are not necessary in this process.

Conclusions

We can see that is possible share some properties to multiple sign in process and use methods for create the object with the necessary values.

I hope this can help you and apply the Builder Pattern concept to other cases.

Resource

https://github.com/enigma2006x/builder-pattern

--

--