Brifing

Composition Over Inheritance in Android ViewModels

How Kotlin's delegation makes ViewModels more flexible

ProAndroidDev - Medium2 min

1Composition vs Inheritance

In 1994, Gang of Four advocated 'Favor object composition over class inheritance'. For shared behaviors in Android ViewModels, composition provides more flexibility than inheritance. Kotlin's 'by' keyword simplifies implementing this pattern. When managing shared state across multiple screens, composition offers a more sustainable solution compared to deep inheritance hierarchies.

2ViewModel's Core Role

Android ViewModels serve as state holders for UI and containers for business logic. When the same state or logic is needed across screens, composition helps decide where it should live. For example, if a Heart component appears on 2 screens and Hexagon on 3 screens, composition provides cleaner abstraction than inheritance for managing their shared state.

3Separation of Concerns

Breaking responsibilities into separate interfaces forms composition's foundation. Defining interfaces like AnalyticsSender and CircleSectionStateHolder allows ViewModels to implement only what they need. Screen1ViewModel might handle Heart, Hexagon and Circle sections. This approach supports single responsibility principle and enhances testability.

4Delegation Mechanism

ViewModel delegates interface implementations to objects received in constructor. Screen1ViewModel delegates HeartSectionStateHolder to heartSectionStateHolder object. All calls automatically forward to delegates. Without Kotlin's 'by' keyword, manual forwarding would require significant boilerplate code for each method.

5Kotlin's Delegation Support

Kotlin provides first-class support for interface delegation via 'by' keyword. A property can delegate interface implementation to another object. This eliminates dozens of boilerplate lines - no need to manually override heartSectionState when using 'by heartSectionStateHolder'. This syntax makes composition as convenient as inheritance.

6Resource Management Advantage

State holders implementing AutoCloseable get cleaned automatically when ViewModel clears. ViewModel constructor accepts Closeable objects that get closed during lifecycle. This prevents leaks for resources like coroutine scopes or listeners. Composition centralizes resource management, reducing error potential.

7Scalability Benefits

Composition makes adding new screens easier. Screen4ViewModel only implements required section interfaces. Changing shared logic only requires updating relevant delegate objects. With inheritance, base class changes could affect all subclasses, increasing technical debt risk especially in large projects.

8Composition as Best Practice

In modern Android architectures, composition is preferred over inheritance. Jetpack ViewModel component was designed to support this pattern. Google's recommended approach improves testability, modularity and maintainability. For multi-module projects and large teams, composition-based design delivers more sustainable results.

Original article: ProAndroidDev - Medium — Android ViewModel'da Kalıtım Yerine Kompozisyon Kullanımı