Mastering Structural Design Patterns in Kotlin & Android: Decorator, Composite & Proxy
Introduction
Mastering Structural Design Patterns in Kotlin & Android: Decorator, Composite & Proxy
Introduction
Software design patterns solve recurring problems in software architecture by providing reusable solutions. Structural Design Patterns focus on how objects and classes are composed to form flexible and scalable systems.
This article covers: 🔹 Decorator Pattern — Extends an object’s functionality dynamically. 🔹 Composite Pattern — Treats individual objects and object groups uniformly. 🔹 Proxy Pattern — Controls access to an object.
Understanding these patterns will enhance your ability to write clean, maintainable, and scalable code in Kotlin and Android development. Let’s dive in! 🚀
1️⃣ Decorator Pattern
What is the Decorator Pattern?
The Decorator Pattern is used to dynamically add or override functionality to objects without modifying their structure. It allows behaviors to be attached at runtime.
✅ Key Features: ✔ Extends existing functionality without modifying the original class. ✔ Overcomes limitations of subclassing by adding new behaviors dynamically. ✔ Used in UI components, logging, and data processing in Android.
When to Use Decorator Pattern?
✔ When you need to modify an object’s behavior dynamically. ✔ When subclassing is not feasible due to complexity or restrictions. ✔ When implementing flexible UI components in Android.
Decorator Pattern in Kotlin (Implementation & Test)
import org.junit.Test
// Base Interface
interface CoffeeMachine {
fun makeSmallCoffee()
fun makeLargeCoffee()
}
// Existing Implementation
class NormalCoffeeMachine : CoffeeMachine {
override fun makeSmallCoffee() {
println("Normal coffee machine making small coffee")
}
override fun makeLargeCoffee() {
println("Normal coffee machine making large coffee")
}
}
// Decorator
class EnhancedCoffeeMachine(private val coffeeMachine: CoffeeMachine) : CoffeeMachine by coffeeMachine {
// Overriding an existing behavior
override fun makeLargeCoffee() {
println("Enhanced coffee machine making large coffee")
}
// Adding a new behavior
fun makeMilkCoffee() {
println("Enhanced coffee machine making milk coffee")
coffeeMachine.makeSmallCoffee()
println("Enhanced coffee machine adding milk to coffee")
}
}
// Test
class DecoratorTest {
@Test
fun testDecorator() {
val normalCoffeeMachine = NormalCoffeeMachine()
val enhancedCoffeeMachine = EnhancedCoffeeMachine(normalCoffeeMachine)
enhancedCoffeeMachine.makeSmallCoffee()
enhancedCoffeeMachine.makeLargeCoffee()
enhancedCoffeeMachine.makeMilkCoffee()
}
}
✅ Android Use Cases: ✔ RecyclerView Item Decoration — Customizing RecyclerView items. ✔ OkHttp Interceptors — Modifying API request and response behavior. ✔ View binding wrappers — Enhancing UI components.
2️⃣ Composite Pattern
What is the Composite Pattern?
The Composite Pattern is used to compose objects into tree structures so that individual objects and groups of objects are treated uniformly.
✅ Key Features: ✔ Encapsulates a hierarchy of objects using a tree-like structure. ✔ Allows treating individual and group objects uniformly. ✔ Used in UI layouts, file systems, and component-based architectures.
When to Use Composite Pattern?
✔ When objects need to be manipulated in a hierarchical structure. ✔ When individual and group objects should be treated the same way. ✔ When dealing with complex UI layouts in Android.
Composite Pattern in Kotlin (Implementation & Test)
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
// Base Component
open class Equipment(open val price: Int, val name: String)
// Composite Component
open class Composite(name: String) : Equipment(0, name) {
private val equipments = ArrayList<Equipment>()
override val price: Int
get() = equipments.sumOf { it.price }
fun add(equipment: Equipment) = apply { equipments.add(equipment) }
}
// Concrete Components
class Computer : Composite("PC")
class Processor : Equipment(100, "Processor")
class HardDrive : Equipment(300, "Hard Drive")
class Memory : Composite("Memory")
class ROM : Equipment(50, "ROM")
class RAM : Equipment(50, "RAM")
// Test
class CompositeTest {
@Test
fun testComposite() {
val memory = Memory().add(ROM()).add(RAM())
val computer = Computer().add(Processor()).add(HardDrive())
assertThat(computer.name).isEqualTo("PC")
assertThat(computer.price).isEqualTo(400)
}
}
✅ Android Use Cases: ✔ Android View Hierarchy — Treating layouts as tree structures. ✔ RecyclerView with multiple view types. ✔ Navigation component structure in Jetpack Compose.
3️⃣ Proxy Pattern
What is the Proxy Pattern?
The Proxy Pattern provides a substitute for another object to control access, add security, or enhance functionality.
✅ Key Features: ✔ Adds additional behavior before or after accessing an object. ✔ Improves security, caching, or lazy loading. ✔ Used in API calls, file loading, and network communication in Android.
When to Use Proxy Pattern?
✔ When delaying expensive object creation until needed. ✔ When adding security, logging, or caching layers. ✔ When restricting access to sensitive data.
Proxy Pattern in Kotlin (Implementation & Test)
import org.junit.Test
// Subject Interface
interface Image {
fun displayImage()
}
// Real Object
class RealImage(private val fileName: String) : Image {
override fun displayImage() {
println("Displaying image: $fileName")
}
private fun loadFromDisk(fileName: String) {
println("Loading from disk: $fileName")
}
init {
loadFromDisk(fileName)
}
}
// Proxy Object
class ProxyImage(private val fileName: String) : Image {
private var realImage: RealImage? = null
override fun displayImage() {
if (realImage == null)
realImage = RealImage(fileName)
realImage!!.displayImage()
}
}
// Test
class ProxyTest {
@Test
fun testProxy() {
val proxyImage = ProxyImage("sample.jpg")
// First time: loads and displays
proxyImage.displayImage()
// Second time: just displays (no loading)
proxyImage.displayImage()
}
}
✅ Android Use Cases: ✔ Glide/Picasso Image Loading — Loading images efficiently. ✔ Retrofit API Interceptors — Caching API responses. ✔ Database Query Caching — Enhancing performance with lazy loading.
Final Thoughts
The Decorator, Composite, and Proxy patterns are powerful tools for structuring your code efficiently in Kotlin and Android development.
💡 Try implementing these patterns in your next Kotlin project!
🚀 Follow for more Kotlin and Android design pattern insights!
메타데이터
- post_id
- 2d3b53ee9191
- slug
- mastering-structural-design-patterns-in-kotlin-android-decorator-composite-proxy-2d3b53ee9191
- url
- https://medium.com/@chetanshingare2991/mastering-structural-design-patterns-in-kotlin-android-decorator-composite-proxy-2d3b53ee9191
- canonical_url
- https://medium.com/@chetanshingare2991/mastering-structural-design-patterns-in-kotlin-android-decorator-composite-proxy-2d3b53ee9191
- author_url
- https://medium.com/@chetanshingare2991
- status
- ok
- fetched_at
- 2026-07-24 14:14:02