34,79 €
Design patterns enable you as a developer to speed up the development process by providing you with proven development paradigms. Reusing design patterns helps prevent complex issues that can cause major problems, improves your code base, promotes code reuse, and makes an architecture more robust.
The mission of this book is to ease the adoption of design patterns in Kotlin and provide good practices for programmers.
The book begins by showing you the practical aspects of smarter coding in Kotlin, explaining the basic Kotlin syntax and the impact of design patterns. From there, the book provides an in-depth explanation of the classical design patterns of creational, structural, and behavioral families, before heading into functional programming. It then takes you through reactive and concurrent patterns, teaching you about using streams, threads, and coroutines to write better code along the way
By the end of the book, you will be able to efficiently address common problems faced while developing applications and be comfortable working on scalable and maintainable projects of any size.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 305
Veröffentlichungsjahr: 2018
Copyright © 2018 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
Commissioning Editor: Richa TripathiAcquisition Editor: Shriram ShekharContent Development Editor: Zeeyan PinheiroTechnical Editor: Ketan KambleCopy Editor: Safis EditingProject Coordinator: Vaidehi SawantProofreader: Safis EditingIndexer: Rekha NairGraphics: Jason MonteiroProduction Coordinator: Aparna Bhagat
First published: June 2018
Production reference: 1130618
Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-78899-801-7
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Alexey Soshin is a software architect with 13 years of experience of making software, mostly for JVM. He started exploring Kotlin even before Kotlin 1.0 was released, and since then, he has been a big enthusiast of the language. He speaks about Kotlin and reactive frameworks at various conferences and meetups and maintains a technical blog. He's also a contributor to Vert.x, a toolkit for building reactive applications onthe Java Virtual Machine.
Ranga Rao Karanam is a programmer, trainer, and architect. He is the founder of in28Minutes—helping 200,000 learners reskill on Cloud native applications, microservices, evolutionary design, high-quality code, DevOps, BDD, TDD, and refactoring. He loves consulting for startups on the development of scalable component-based cloud-native applications and following modern development practices, such as BDD, continuous delivery, and DevOps.
Ranga likes to play cricket and tennis, and he is a regular hiker. His dream is to spend a year hiking in the Himalayas.
Ganesh Samarthyam is a co-founder of CodeOps Technologies, a software technology, consultancy, and training company based in Bangalore. He has 16 years of experience in the IT industry, and his latest book, Refactoring for Software Design Smells by Morgan Kaufmann/Elsevier, has been translated into Korean and Chinese. Ganesh loves exploring anything and everything about technology in his free time.
If you're interested in becoming an author for Packt, please visit authors.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Title Page
Copyright and Credits
Hands-On Design Patterns with Kotlin
Dedication
Packt Upsell
Why subscribe?
PacktPub.com
Contributors
About the author
About the reviewers
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
Getting Started with Kotlin
Basic language syntax and features
Multi-paradigm
Code structure
No semicolons
Naming conventions
Packages
Types
Type inference
val versus var
Comparison
Null safety
Declaring functions
Control flow
Using the if expression
Using the when expression
String interpolation
Classes and inheritance
Classes
Inheritance
Constructors
Properties
Data classes
More control flow – loops
The for loop
For-each loop
While loop
Extension functions
Introduction to design patterns
What are design patterns?
Design patterns in real life
Design process
Why use design patterns in Kotlin?
Summary
Working with Creational Patterns
Singleton
Factory Method
Factory
Static Factory Method
Advantages of the Static Factory Method
Caching
Subclassing
Static Factory Method in Kotlin
Companion object
Abstract Factory
Abstract Factory in action
Introduction to generics in Kotlin
Back to our bases
Making improvements
Builder
Composing an email
Collection types in Kotlin
Creating an email – first attempt
Creating an email – second attempt
Creating an email – the Kotlin way
Creating an email – the Kotlin way – second attempt
Prototype
Building your own PC
Starting from a prototype
Summary
Understanding Structural Patterns
Decorator
Enhancing a class
Operator overloading
Dude, where's my map?
The great combinator
Caveats
Adapter
Different adapters
Adapters in the real world
Caveats of using adapters
Bridge
Bridging changes
Type aliases
You're in the army now
Constants
A lethal weapon
Composite
Get together
The Squad
Varargs and secondary constructors
Counting bullets
Facade
Keep it simple
Flyweight
Being conservative
Saving memory
Proxy
A short detour into the RMI world
A replacement
Lazy delegation
Summary
Getting Familiar with Behavioral Patterns
Strategy
Fruit arsenal
Citizen function
Switching sides
Iterator
One, two... many
Running through the values
State
Fifty shades of State
State of the Nation
Command
Undoing commands
Chain of responsibility
Interpreter
We need to go deeper
A language of your own
Taking a break
Call suffix
Mediator
Trouble in the Jungle
The middleman
Flavors
Caveats
Memento
Remembrance
Visitor
Writing a crawler
Template method
Observer
Animal Choir
Summary
Functional Programming
Why functional programming?
Immutability
Tuples
Value mutation
Immutable collections
Functions as values
Higher-order functions
Pure functions
Currying
Memoization
Expressions, not statements
Pattern matching
Recursion
Summary
Streaming Your Data
The it notation
The map() function
Filter family
Find family
Drop family
Sort family
ForEach
Join family
Fold/Reduce
Flat family
Slice
Chunked
Zip/Unzip
Streams are lazy, collections are not
Sequences
Summary
Staying Reactive
Reactive principles
Responsiveness
Resiliency
Elasticity
Message-driven
Reactive extension
Hot Observable
Multicast
Subject
ReplaySubject
BehaviorSubject
AsyncSubject
SerializedSubject
Flowables
Holding state
FlowableProcessor
Batching
Throttling
Summary
Threads and Coroutines
Threads
Thread safety
Threads are expensive
Coroutines
Starting coroutines
Jobs
Coroutine starvation
Coroutines under the hood
Fixing starvation
Waiting for a coroutine
Canceling a coroutine
Returning results
Setting timeouts
Parent jobs
Channels
Producers
Actors
Summary
Designed for Concurrency
Active Object
Testing
Deferred value
Barrier
CountDownLatch
Data class as Barrier
Scheduler
Understanding contexts
Pipelines
Establishing a pipeline
The fan-out design pattern
The fan-in design pattern
Managing workers
Buffered channels
Unbiased select
Mutexes
Selecting on close
Sidekick channel
Deferred channel
Summary
Idioms and Anti-Patterns
Let
Apply
Also
Run
With
Instance checks
Try-with-resources
Inline functions
Reified
Constants
Constructor overload
Dealing with nulls
Explicit async
Validation
Sealed, not enumerated
More companions
Scala functions
Summary
Reactive Microservices with Kotlin
Getting started with Vert.x
Routing
Handling requests
Verticles
Subrouting
Testing
Helper methods
Working with databases
Managing configuration
Managing the database
EventBus
Consumer
Producer
More testing
Summary
Other Books You May Enjoy
Leave a review - let other readers know what you think
Design patterns enable you as a developer to speed up the development process by providing tested, proven development paradigms. Reusing design patterns helps prevent complex issues that can cause major problems and improves your code base, promotes code reuse, and makes the architecture more robust.
The mission of this book is to ease the adoption of design patterns in Kotlin and provide good practices for programmers.
The book begins by showing you the practical aspects of smarter coding in Kotlin, explaining the basic Kotlin syntax and the impact of design patterns. Furthermore, the book provides an in-depth explanation of the classic design patterns, such as Creational, Structural, and Behavioral, before heading into functional programming. It then takes you through Reactive and Concurrent patterns, teaching you about Streams, Threads, and Coroutines to write better code. Toward the end, you will learn about the latest trends in architecture, exploring the design patterns for microservices, and discuss the considerations when choosing between different architectures, such as microservices and MVC.
By the end of the book, you will be able to efficiently address common problems faced while developing applications and be comfortable working on scalable and maintainable projects of any size.
This book is for developers who would like to master design patterns with Kotlin in order to build efficient and scalable applications. Basic Java or Kotlin programming knowledge is assumed.
Chapter 1,Getting Started with Kotlin, covers basic language concepts and syntax, such as types, functions, classes, and flow control structures.
Chapter 2,Working with Creational Patterns, explains what classical creational patterns are embedded into the language and how to implement those that aren't. It discusses Singleton and Factory, among others.
Chapter 3,Understanding Structural Patterns, focuses on how to extend the functionality of our objects and adapt to changes.
Chapter 4,Getting Familiar with Behavioral Patterns, explains how can we alter object behavior at runtime, iteration over complex data structures, and communication between objects using the Observable design pattern.
Chapter 5,Functional Programming, dives into the principles of functional programming and how they fit into Kotlin. Topics such as data immutability and functions as a first-class value will be discussed in depth.
Chapter 6,Streaming Your Data, shows how applying the principles of functional programming help us process potentially infinite streams of incoming data.
Chapter 7, Staying Reactive, explains what reactive principles are and gives extensive examples based on the Reactive Extensions framework, better known as simply Rx.
Chapter 8, Threads and Coroutines, shows how easy it to work with concurrent code in Kotlin, making use of its lightweight thread model.
Chapter 9, Designed for Concurrency, covers design patterns that help us process many tasks at the same time, using coroutines.
Chapter 10, Idioms and Anti-Patterns, provides guidelines on some best practices and pitfalls that you may encounter while developing in Kotlin.
Chapter 11, Reactive Microservices with Kotlin, goes over a detailed example of writing a microservice using Kotlin, Vert.x, and PostgreSQL.
In this book, we assume that the reader has basic knowledge of Java programming language and what JVM is.
It is also assumed that the reader is comfortable working with the command line.
A few command-line examples we use in this book are based on OSX, but could be easily adapted for Windows or Linux.
You can download the example code files for this book from your account at www.packtpub.com. If you purchased this book elsewhere, you can visit www.packtpub.com/support and register to have the files emailed directly to you.
You can download the code files by following these steps:
Log in or register at
www.packtpub.com
.
Select the
SUPPORT
tab.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box and follow the onscreen instructions.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR/7-Zip for Windows
Zipeg/iZip/UnRarX for Mac
7-Zip/PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Hands-on-Design-Patterns-with-Kotlin. In case there's an update to the code, it will be updated on the existing GitHub repository.
We also have other code bundles from our rich catalog of books and videos available athttps://github.com/PacktPublishing/. Check them out!
Feedback from our readers is always welcome.
General feedback: Email [email protected] and mention the book title in the subject of your message. If you have questions about any aspect of this book, please email us at [email protected].
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you have found a mistake in this book, we would be grateful if you would report this to us. Please visit www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details.
Piracy: If you come across any illegal copies of our works in any form on the Internet, we would be grateful if you would provide us with the location address or website name. Please contact us at [email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, please visit authors.packtpub.com.
Please leave a review. Once you have read and used this book, why not leave a review on the site that you purchased it from? Potential readers can then see and use your unbiased opinion to make purchase decisions, we at Packt can understand what you think about our products, and our authors can see your feedback on their book. Thank you!
For more information about Packt, please visit packtpub.com.
In this chapter, we'll cover basic Kotlin syntax, and discuss what design patterns are good for and why they should be used in Kotlin.
The goal of this chapter is not to cover the entire language vocabulary, but to get you familiar with some basic concepts and idioms. The following chapters will slowly expose you to more language features as they become relevant to the design patterns we'll discuss.
In this chapter, we will cover the following topics:
Basic language syntax and features
Introduction to design patterns
Whether you come from Java, C#, Scala or any other statically typed programming language, you'll find Kotlin syntax quite familiar. This is not by coincidence, but to make the transfer to this new language as smooth as possible for those with previous experience in other languages. Besides that familiarity, Kotlin brings a vast amount of features, such as better type safety. As we move ahead, you'll notice that all of them are attempting to solve real-world problems. That pragmatic approach is very consistent across the language. For example, one of the strongest sides of Kotlin is complete Java interoperability. You can have Java and Kotlin classes alongside each other, and freely use any library that is available in Java for a Kotlin project.
To summarize, the goals of language are as follows:
Pragmatism
Having clear syntax
Being type-safe
Interoperability
The first chapter will discuss how these goals are achieved.
Some of the major paradigms in programming languages are procedural, object-oriented, and functional paradigms.
Being practical, Kotlin allows for any of these paradigms. It has classes and inheritance, coming from the object-oriented approach. It has higher-order functions from functional programming. But you don't have to wrap everything in classes if you don't want to. You can structure your entire code as just a set of procedures and structs. You will see how all these approaches come together, as different examples will use different paradigms to solve the problems discussed.
The first thing you'll need to do when you start programming in Kotlin is create a new file. Kotlin's extension is usually .kt.
Unlike Java, there's no strong relationship between the filename and class name. You can put as many public classes in your file as you want, as long as the classes are related to one another and your file doesn't grow too long to read.
In Java, every line of code must be terminated with a semicolon:
System.out.println("Hello")
; //<- This is a semicolon
System.out.println("World");
//<- I still see you, semicolon
But Kotlin is a pragmatic language. So, instead, it infers during compilation where it should put the semicolons:
println("Hello")
//<- No semicolon here
println("World")
//<- Not here
Most of the time, you won't need to put semicolons in your code. They're considered optional.
As a convention, if your file contains a single class, name your file the same as your class.
If your file contains more than one class, then the filename should describe the common purpose of those classes. Use CamelCase when naming your files, as per the Kotlin Coding Conventions: https://kotlinlang.org/docs/reference/coding-conventions.html#naming-rules.
It wouldn't be convenient to have all your classes and functions in the same folder or under the same namespace. That's the reason Kotlin, similar to many other languages, uses the notion of a package.
Like Java, Kotlin uses packages:
package me.soshin.controllers
If you're mixing Java and Kotlin, Kotlin files should follow Java package rules.
In purely Kotlin projects, common package prefixes can be omitted from the folder structure. For example, if all your projects are under the me.soshin package, place your controllers in the /controllers folder and not in the /me/soshin/controllers folder like Java does.
We'll start with the Kotlin type system, and compare it to what Java provides.
Everything is an object in Java. If you have a method that doesn't rely on any state, it still must be wrapped by a class. You're probably familiar with a lot of Util classes in Java that only have static methods, and their only purpose is to satisfy the language requirements and bundle those methods together.
In Kotlin, a function can be declared outside of a class instead of the following code:
public class MyFirstClass {
public static void main(String[] args) { System.out.println("Hello world"); }}
It's enough to have:
fun main(args: Array<String>) { println("Hello, world!")}
Functions declared outside of any class are already static.
The keyword to declare a function is fun. The argument type comes after the argument name, and not before. And if the function doesn't return anything, the return type can be omitted completely.
What if you do want to declare the return type? Again, it will come after the function declaration:
fun getGreeting():
String
{ return "Hello, world!"}fun main(args: Array<String>) { println(getGreeting())}
There are lots of other topics regarding function declarations, such as default and named arguments, default parameters, and variable numbers of arguments. We'll introduce them in the following chapters, with relevant examples.
One could say that control flow is the bread and butter of writing programs. We'll start with two conditional expressions: if and when.
What if (no pun intended) we want to have more conditions in our if statement?
In Java, we use the switch statement. In Kotlin, there's a when expression, which is a lot more powerful, since it can embed some other Kotlin features.
Let's create a method that's based on the amount of money that will give cause to suggest a nice birthday gift:
fun suggestGift(amount : Int) : String { return
when
(amount) {
in
(0..10) -> "a book" in (10..100) -> "a guitar" else -> if (amount < 0) "no gift" else "anything!" }}
As you can see, when also supports a range of values. The default case is covered by the else block. In the following examples, we will elaborate on even more powerful ways to use this expression.
As a general rule, use when if you have more than two conditions. Use if for simple checks.
Although Kotlin is multi-paradigm, it has a strong affinity to the Java programming language, which is based on classes. Keeping Java and JVM interoperability in mind, it's no wonder that Kotlin also has the notion of classes and classical inheritance.
Our DungeonMaster looks a bit awkward now, since it can proclaim the start of only one game. Let's add a non-empty constructor to our abstract class to fix that:
abstract class
AbstractDungeonMaster(
private val
gameName
: String) {
fun
startGame
() {
println
(
"Game
$
gameName
has started!"
) }}
Now, our DungeonMaster must receive the name of the game and pass it to the abstract class:
open class
DungeonMaster(gameName: String): Greeter
,
AbstractDungeonMaster(gameName)
What if we wanted to extend DungeonMaster by having an EvilDungeonMaster?
In Java, all classes can be extended, unless they're marked final. In Kotlin, no class can be extended, unless it's marked open. The same goes for functions in abstract classes. That's the reason why we declared DungeonMaster as open in the first place.
We'll change AbstractDungeonMaster a bit again to give more power to the evil ruler:
open
fun
startGame
() { // Everything else stays the same}
Now, we add the following to our EvilDungeonMaster implementation:
class
EvilDungeonMaster(
private val
awfulGame
: String) : DungeonMaster(awfulGame) {
override fun
sayHello
() {
println
(
"Prepare to die! Muwahaha!!!"
) }
override fun
startGame
() {
println
(
"
$
awfulGame
will be your last!"
) }}
Whereas in Java, @Override is an optional annotation, in Kotlin it is a mandatory keyword.
You cannot hide supertype methods, and code that doesn't use override explicitly won't compile.
Remember how Kotlin is all about productiveness? One of the most common tasks for Java developers is to create another Plain Old Java Object (POJO). If you're not familiar with POJO, it is basically an object that only has getters, setters, and an implementation of equals or hashCode methods.
This task is so common that Kotlin has it built into the language:
data class User (val username : String, val password : String)
This will generate a class with two getters and no setters (note the val part), which will also implement equals, hashCode, and clone functions in the correct way.
The introduction of data classes is one of the biggest improvements in reducing the amount of boilerplate in the language.
Now let's discuss another common control structure—a loop. Loops are a very natural construct for most developers. Without loops, it would be very hard to repeat the same block of code more than once (although we will discuss how to do that without loops in later chapters).
