Reader small image

You're reading from  Kotlin Design Patterns and Best Practices - Second Edition

Product typeBook
Published inJan 2022
Reading LevelBeginner
PublisherPackt
ISBN-139781801815727
Edition2nd Edition
Languages
Right arrow
Author (1)
Alexey Soshin
Alexey Soshin
author image
Alexey Soshin

Alexey Soshin is a software architect with 15 years of experience in the industry. He started exploring Kotlin when Kotlin was still in beta, and since then has been a big enthusiast of the language. He's a conference speaker, published writer, and the author of a video course titled Pragmatic System Design.
Read more about Alexey Soshin

Right arrow

Chapter 2: Working with Creational Patterns

In this chapter, we'll cover how classic creational patterns are implemented using Kotlin. These patterns deal with how and when you create your objects. For each design pattern, we will discuss what it aims to achieve and how Kotlin accommodates those needs.

We will cover the following topics in this chapter:

  • Singleton
  • Factory Method
  • Abstract Factory
  • Builder
  • Prototype

Mastering these design patterns will allow you to manage your objects better, adapt well to changes, and write code that is easy to maintain.

Technical requirements

For this chapter, you will need to install the following:

You can find the code files for this chapter on GitHub at https://github.com/PacktPublishing/Kotlin-Design-Patterns-and-Best-Practices/tree/main/Chapter02.

Singleton

Singleton – the most popular bachelor in town. Everybody knows him, everybody talks about him, and everybody knows where to look for him.

Even people who don't like using design patterns will know Singleton by name. At one point, it was even proclaimed an anti-pattern, but only because of its wide popularity.

So, for those who are encountering it for the first time, what is this design pattern all about?

Usually, if you have a class, you can create as many instances of it as you want. For example, let's say that we both are asked to list all of our favorite movies:

val myFavoriteMovies = listOf("Black Hawk Down", "Blade   Runner")
val yourFavoriteMovies = listOf(...)

Note that we can create as many instances of List as we want, and there's no problem with that. Most classes can have multiple instances.

Next, what if we both want to list the best movies in the Quick and Angry series?

val myFavoriteQuickAndAngryMovies...

Factory Method

The Factory Method design pattern is all about creating objects.

But why do we need a method to create objects? Isn't that what constructors are for?

Well, constructors have limitations.

As an example, imagine we're building a game of chess. We would like to allow our players to save the state of the game into a text file and then restore the game from that position.

Since the size of the board is predetermined, we only need to record the position and type of each piece. We'll use algebraic notation for this – for example, the Queen piece at C3 will be stored in our file as qc3, the pawn piece at A8 will be stored as pa8, and so on.

Let's assume that we already read this file into a list of strings (which, by the way, would be an excellent application of the Singleton design pattern we discussed earlier).

Given the list of notations, we would like to populate our board with them:

// More pieces here
val notations = listOf...

Abstract Factory

Abstract Factory is a greatly misunderstood design pattern. It has a notorious reputation for being very complex and bizarre. Actually, it's quite simple. If you understood the Factory Method design pattern, you'll understand this one in no time. This is because the Abstract Factory design pattern is a factory of factories. That's all there is to it. The factory is a function or class that's able to create other classes. In other words, an abstract factory is a class that wraps multiple factory methods.

You may understand this and still wonder what the use of such a design pattern may be. In the real world, the Abstract Factory design pattern is often used in frameworks and libraries that get their configuration from files. The Spring Framework is just one example of these.

To better understand how the design pattern works, let's assume we have a configuration for our server written in a YAML file:

server: 
    ...

Builder

Sometimes, our objects are very simple and have only one constructor, be it an empty or non-empty one. But sometimes, their creation is very complex and based on a lot of parameters. We've seen one pattern already that provides a better constructor – the Static Factory Method design pattern. Now, we'll discuss the Builder design pattern, which will help us create complex objects.

As an example of such an object, imagine we need to design a system that sends emails. We won't implement the actual mechanism of sending them, we will just design a class that represents it.

An email may have the following properties:

  • An address (at least one is mandatory)
  • CC (optional)
  • Title (optional)
  • Body (optional)
  • Important flag (optional)

We can describe an email in our system as a data class:

data class Mail_V1(
    val to: List<String>,
    val cc: List<String>?,
  &...

Prototype

The Prototype design pattern is all about customization and creating objects that are similar but slightly different. To understand it better, Let's look at an example.

Imagine we have a system that manages users and their permissions. A data class representing a user might look like this:

data class User(
    val name: String,
    val role: Role,
    val permissions: Set<String>,
) {
    fun hasPermission(permission: String) = permission in       permissions
}

Each user must have a role, and each role has a set of permissions.

We'll describe a role as an enum class:

enum class Role {
    ADMIN,
    SUPER_ADMIN,
    REGULAR_USER
}

The enum classes are a way to represent a collection of constants. This is more convenient than representing a role as a string, for example, as...

Summary

In this chapter, we have learned when and how to use creational design patterns. We started by discussing how to use the object keyword to construct a singleton class, and then we discussed the use of companion object if you need a Static Factory Method. We also covered how to assign multiple variables at once using destructuring declarations.

Then, we discussed smart casts, and how they can be applied in the Abstract Factory design pattern to create families of objects. We then moved to the Builder design pattern and learned that functions can have default parameter values. We then learned that we can refer to their arguments using not only positions but also names.

Finally, we covered the copy() function of the data classes, and how it helps us when implementing the Prototype design pattern to produce similar objects with slight changes. You should now understand how to use creational design patterns to better manage your objects.

In the next chapter, we'll...

Questions

  1. Name two uses for the object keyword we learned about in this chapter.
  2. What is the apply() function used for?
  3. Provide one example of a Static Factory Method.
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Kotlin Design Patterns and Best Practices - Second Edition
Published in: Jan 2022Publisher: PacktISBN-13: 9781801815727
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Alexey Soshin

Alexey Soshin is a software architect with 15 years of experience in the industry. He started exploring Kotlin when Kotlin was still in beta, and since then has been a big enthusiast of the language. He's a conference speaker, published writer, and the author of a video course titled Pragmatic System Design.
Read more about Alexey Soshin