Real World Example

Payment Methods at Checkout

Paytm, PhonePe and Amazon accept UPI, cards and wallets. Checkout depends on a PaymentMethod interface, so adding a new method (e.g. Pay Later) does not change the checkout code.

Example

interface PaymentMethod {
    val displayName: String
    fun pay(amount: Double): Boolean
    fun fee(amount: Double): Double = 0.0     // default: free
}

class Upi(private val vpa: String) : PaymentMethod {
    override val displayName = "UPI ($vpa)"
    override fun pay(amount: Double) = amount <= 100000
}

class Card(private val last4: String) : PaymentMethod {
    override val displayName = "Card **** $last4"
    override fun pay(amount: Double) = true
    override fun fee(amount: Double) = amount * 0.02
}

class Wallet(private var balance: Double) : PaymentMethod {
    override val displayName = "Wallet"
    override fun pay(amount: Double): Boolean {
        if (amount > balance) return false
        balance -= amount
        return true
    }
}

fun checkout(amount: Double, method: PaymentMethod) {
    val total = amount + method.fee(amount)
    val ok = method.pay(total)
    println("%-18s total %8.2f -> %s".format(method.displayName, total, if (ok) "SUCCESS" else "FAILED"))
}

fun main() {
    checkout(1200.0, Upi("asha@okicici"))
    checkout(1200.0, Card("4242"))
    checkout(1200.0, Wallet(500.0))
}

Output

UPI (asha@okicici) total  1200.00 -> SUCCESS
Card **** 4242     total  1224.00 -> SUCCESS
Wallet             total  1200.00 -> FAILED

Android: Repository Interface

In Android apps the ViewModel depends on an interface, not a concrete class. The real implementation calls Retrofit/Room; a fake one is used in tests.

interface ProductRepository {
    suspend fun getProducts(): List<Product>
}

class NetworkProductRepository(private val api: ShopApi) : ProductRepository {
    override suspend fun getProducts() = api.fetchProducts()
}

class FakeProductRepository : ProductRepository {
    override suspend fun getProducts() = listOf(Product(1, "Test Phone", 9999.0))
}

class ProductViewModel(private val repo: ProductRepository) : ViewModel()