Design patterns you use every day

Architecture and dependency injection Junior Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Predict the output

Which pattern does this code use?

class TimingRepository(private val inner: UserRepository) {
    suspend fun user(id: String): User {
        val start = System.nanoTime()
        return inner.user(id).also {
            log("user($id) took ${(System.nanoTime() - start) / 1_000_000} ms")
        }
    }
}
Options
Hint 1 of 1

What does it do with the inner object?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Decorator

Correct. It wraps another object with the same job and adds behaviour around it.

Why not the others?
  • B Factory. It doesn't create objects for callers.
  • C Observer. Nothing subscribes to changes.
  • D Singleton. Nothing limits the number of instances.

30-second answer

Observer: Flows and StateFlow. Builder: NotificationCompat.Builder, OkHttpClient.Builder. Factory: ViewModel factories and Hilt providers. Adapter: RecyclerView adapters and Retrofit converters. Facade: a repository hiding several sources. Strategy: interchangeable implementations behind an interface. Decorator: a class that wraps another implementation of the same interface to add behaviour. Chain of responsibility: OkHttp interceptors, each passing the call on.

Practise saying it · 30 s. No recording, just a timer

Name patterns in everyday Android code.

Say your answer out loud, then check which of these points you covered:

  • Observer, Builder, Factory, Adapter
  • Facade and Decorator
  • Kotlin replaces some patterns
  • Use names to communicate

Deep dive

Kotlin features replace some patterns: named and default arguments make many builders unnecessary for your own classes.

object gives a singleton, but DI singletons are easier to test.

Delegation with by makes decorators short.

Name the pattern only when it helps the team talk about the design.

Common mistakes

  • Writing a builder for a Kotlin class with default arguments.
  • Using singletons as global state.
  • Forcing patterns where a function would do.

Senior take & follow-ups

Tie each pattern to a library people know; it proves practical understanding.

Follow-up questions

Think of your answer first, then open the hint.

  1. Why are builders less common in Kotlin?

    Show hint

    Default and named arguments cover most optional parameters.

  2. Which pattern are OkHttp interceptors?

    Show hint

    Chain of responsibility, with each one able to wrap the call.

Similar on iOS: The observer pattern iOS uses delegates and Combine where Android uses Flows and listeners.

Suggest a fix if something here is wrong or out of date.