Design Patterns in Android Development
System Design
Design Patterns in Android Development
Akshay Nandwana
January 4, 2025
5 min read
77 views

Design patterns are proven solutions to common problems in software design. They help structure code, improve reusability, and maintain consistency. Below, we explore various design patterns and their applications in Android development.

πŸ—οΈ Singleton Pattern

This pattern ensures a single instance of a class. Common use cases in Android include SharedPreferences, Retrofit, and Room database instances.

Example:

kotlin
object RetrofitInstance {
    val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .build()
}

πŸ‘· Builder Pattern

The Builder Pattern helps construct complex objects step by step. In Android, AlertDialog.Builder or Notification.Builder are great examples.

Example:

kotlin
val alertDialog = AlertDialog.Builder(this)
    .setTitle("Title")
    .setMessage("Message")
    .setPositiveButton("OK", null)
    .create()
alertDialog.show()

πŸ“’ Observer Pattern

The Observer Pattern is used to notify observers of changes. In Android, LiveData is commonly used.

Example:

javascript
viewModel.liveData.observe(this) { data ->
    textView.text = data
}

πŸ“Š Repository Pattern

This pattern abstracts data sources and provides a clean API. It’s widely used with Room and Retrofit.

Example:

kotlin
class Repository(private val api: ApiService, private val dao: Dao) {
    fun fetchData() = api.getData()
    fun saveData(data: List<Data>) = dao.insertAll(data)
}

πŸ“‘ Repository + UseCase Pattern

Combine Repository and UseCase patterns for better separation of concerns.

Example:

kotlin
class GetUserUseCase(private val repository: UserRepository) {
    fun execute() = repository.getUser()
}

🏭 Factory Pattern

The Factory Pattern is used to create objects without specifying the exact class. In Android, FragmentFactory can be used to dynamically create fragments.

Example:

kotlin
class CustomFragmentFactory : FragmentFactory() {
    override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
        return when (className) {
            MyFragment::class.java.name -> MyFragment(arguments)
            else -> super.instantiate(classLoader, className)
        }
    }
}

🧳 Prototype Pattern

The Prototype Pattern involves cloning objects to avoid expensive object creation. In Android, you can use this pattern for UI elements.

Example:

kotlin
val originalView = TextView(context)
val clonedView = originalView.copy()

🧩 Adapter Pattern

This pattern converts one interface into another. The RecyclerView.Adapter is a common example in Android.

Example:

kotlin
class MyAdapter(private val data: List<String>) : RecyclerView.Adapter<MyViewHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_view, parent, false)
        return MyViewHolder(view)
    }
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bind(data[position])
    }
    override fun getItemCount() = data.size
}

🏰 Facade Pattern

The Facade Pattern provides a simplified interface to a larger, more complex system. MediaPlayer in Android is a great example.

Example:

kotlin
val mediaPlayer = MediaPlayer().apply {
    setDataSource("audio_file.mp3")
    prepare()
    start()
}

πŸ› οΈ Decorator Pattern

This pattern dynamically adds functionality to an object. Wrapping InputStream in BufferedInputStream is an example.

Example:

kotlin
val inputStream = FileInputStream(file)
val bufferedStream = BufferedInputStream(inputStream)

πŸŒ‰ Bridge Pattern

The Bridge Pattern decouples abstraction from implementation. In Android, it can be seen in custom views.

Example:

kotlin
class CustomView(context: Context) : View(context) {
    override fun onDraw(canvas: Canvas) {
        // Custom drawing logic
    }
}

πŸ—οΈ Composite Pattern

This pattern composes objects into tree structures. The ViewGroup and View hierarchy in Android are examples.

Example:

kotlin
val linearLayout = LinearLayout(context).apply {
    orientation = LinearLayout.VERTICAL
    addView(TextView(context))
    addView(Button(context))
}

πŸ‘₯ Strategy Pattern

This pattern defines a family of algorithms and lets you choose one at runtime. In Android, it is used for handling different UI states.

Example:

kotlin
val strategy = if (isTablet) TabletLayoutStrategy() else PhoneLayoutStrategy()
strategy.applyLayout()

πŸ’‘ Command Pattern

The Command Pattern encapsulates user actions as objects. Button clicks in Android can follow this pattern.

Example:

kotlin
val command = ClickCommand(Button(context))
command.execute()

🧲 Memento Pattern

The Memento Pattern saves an object’s state. SavedStateHandle in ViewModel is an example.

Example:

kotlin
class MyViewModel(private val state: SavedStateHandle) : ViewModel() {
    val data = state.getLiveData("key")
}

πŸ”„ State Pattern

The State Pattern manages state-dependent behavior. In Android, it can be used for media player states.

Example:

kotlin
class MediaPlayerState {
    fun play() { /* ... */ }
    fun pause() { /* ... */ }
}

πŸ’» Service Locator Pattern

Simplify dependency lookup for services like LocationManager or NotificationManager.

Example:

kotlin
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager

Note: You don’t have to memorize all these patterns by heart. Focus on understanding the core principles and applying them when needed in your projects. It’s a journey, not a race!

Akshay Nandwana
Founder AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
https://www.androidengineers.in/courses

Share This Article
Stay Updated

Get the latest Android development articles delivered to your inbox.